【问题标题】:MS Access Pass Form Through FunctionMS Access 通行证功能
【发布时间】:2018-03-13 00:19:18
【问题描述】:

我正在尝试创建一个函数,允许我使用各种命令按钮,而不必每次都重新创建代码。

为此,我必须通过函数传递表单名称

功能:

public Function NewRecord(controlForm, focusForm)
focusForm.SetFocus
DoCmd.GoToRecord , , acNewRecord
controlForm.SetFocus

controlForm - 这是类似于 Me 函数的主要表单

focusForm - 这不仅适用于主表单,而且当我创建子表单时,我必须将焦点放在子表单上才能使命令正常工作。

要调用该函数,我执行了以下操作:

public sub Command19_Click()
Dim controlForm
Dim focusForm

Set controlForm = Forms![frm_Sales_CustomerProfile]
Set focusForm = Forms![frm_Sales_CustomerProfile]

Call NewRecord(controlForm, focusForm)

End Sub

我得到这个错误状态:编译错误:无效使用属性。

【问题讨论】:

  • 您的错误是因为您调用了表单的属性NewRecord!如果您不使用强名称,就会发生这种情况。试试MyModulname.NewRecord(controlForm, focusForm)。您的第二种形式参数已过时。如果它是子表单,只需传递子表单引用。您可以使用frm.Parent 访问主窗体。

标签: ms-access vba ms-access-2010 ms-access-2016


【解决方案1】:

您使用已在此上下文中(表单)使用的标识符而不是使用强名称(NameOfLibrary.NameOfFunction)被困。NewRecord是表单属性,所以Invalid Use Of Property有意义。如果您使用MyModulName.NewRecord(frm1,frm2)一切都很好。如果您在 Module òr Class 中使用NewRecordin,它也可以工作,因为没有同名的属性(我假设;-))。

说实话,我也不使用强名称(数据库或记录集对象除外,因为我也被困在那里,假设是 DAO,使用 ADODB),但专业人士建议这样做,现在我们知道为什么了!

您的函数应该只有一个参数,因为如果您需要该表单NewRecord(frm as Access.Form)(请注意强名称!),则仅传递子表单引用就足够了。您可以使用 Set mfrm = frm.Parent 轻松引用主窗体

你的代码;

Public Function FrmNewRecord(frm As Access.Form)
    frm.Recordset.AddNew
End Function

Public Sub Command19_Click()
    FrmNewRecord(Forms![frm_Sales_CustomerProfile]) ' mainform
    FrmNewRecord(Forms![frm_Sales_CustomerProfile]!sfrmControl.Form) ' subform
End Sub

您在代码中两次传递相同的表单,有什么原因吗?如果Forms[frm_Sales_CustomerProfile] 包含Command19,则使用Me。 我删除了.SetFocuspart 是没有必要或有任何理由设置焦点?为什么 NewRecord 是一个函数?不返回任何东西。 顺便说一句:我正在研究 aSubForms(frm)function ,它返回所有子表单的集合。

代码:

'SubForms(frm As Access.Form) returns a collection of all subform references in frm

Public Function SubForms(frm As Access.Form) As VBA.Collection
Dim ctr As Access.Control
Dim sfrm As Access.Form
Dim col As New VBA.Collection

For Each ctr In frm.Controls
    If ctr.ControlType = acSubform Then
        On Error Resume Next
        Set sfrm = ctr.Form
        If Err.Number = 0 Then
            col.Add sfrm, sfrm.Name
        End If
        On Error GoTo 0
    End If
Next ctr
Set SubForms = col
End Function

【讨论】:

  • 我不确定我是否在关注你。我明白您为什么要使用硬名称,但我不明白您建议的集成过程。我将嵌套 2 个子表单,包括这 3 个的主要表单。每个人都需要一个新的记录按钮。我认为制作一个可以轻松引用新记录命令的函数会更容易。我想我要问的是你如何设置硬名称。我以前从未使用过它们,所以对我来说有点新。
  • 你的硬名字是什么? controlForm?它是一个变量,在设置后带有指向表单对象的指针,例如 var for.Forms![frm_Sales_CustomerProfile]what 只是 Forms.Item("frm_Sales_CustomerProfile") 其中 Forms 是所有表单的集合,由其名称指定为键。如果是第一种形式,您可以使用Forms.Item(1)通过索引访问集合。
  • 好吧,只是为了确保我理解。我通过函数传递了带有 Item 的那个,并通过变量名引用它。
  • 是的,就像您之前对 2 个对象所做的那样。如果您更喜欢传递主窗体和子窗体,只需添加另一个窗体对象作为函数的参数。我只是跳过了对controlFomfocusForm的评估,因为你不需要这样做,但你可以。
  • 我试过Private Sub Command19_Click() 然后设置变量Dim control form。设置变量Set controlForm = Forms.Item(frm_Sales_CustomerProfile),调用函数Call NewRecord(controlForm)。该函数与以前相同,但我有一个变量Public Function NewRecord(controlForm),并更改了索引controlForm(1).SetFocuscontrolForm(1).SetFocus 的变量。我仍然得到财产问题。我做错了吗?
【解决方案2】:

作为构建自定义菜单栏或功能区的一般规则,您可以编写这样的“表单”中性代码:

公共函数 MyDelete(strPrompt As String, strTable As String)

  Dim strSql        As String
  Dim f             As Form
  Set f = Screen.ActiveForm
  If MsgBox("Delete this " & strPrompt & " record?", _
                vbQuestion + vbYesNoCancel, "Delete?") = vbYes Then

所以请注意我们根本不需要传递表单名称 - 上面的代码只是将活动屏幕作为变量“f”。

此时您可以做任何事情,就像代码在表单中一样。

所以

Me.Refresh    (code inside the form)

变成

f.Refresh

所以这里的关键概念是你不需要传递当前的活动表单,因为 screenActive 表单无论如何都会让你获得当前的表单对象。

但是,对于子表单和“普通”类型的代码,上面的代码就崩溃了,因为 screen.ActiveForm 将返回主表单,而不是子表单实例。

所以作为第二种推荐的方法,总是像这样简单地传递当前上下文表单对象“me”:

Call MySub(me)

你定义你的 sub 像:

Sub MySub(f as form)

现在在这段代码中,我们可以通过使用“f”代替“me”来引用“anything”

f.Refresh

因此,如果您曾经使用过子表单,只需传递“我”即可。有了以上信息,那么你的代码就变成了:

public sub Command19_Click()

   Call NewRecord(me)


End Sub

NewReocrd 变成:

Sub NewRecord(f as form)

现在在您的 newreocrd 代码中,您可以使用对象的“任何东西”,例如:

f.Name    ' get name of the form.

City = f.City    ' get value of city control

所以传递“整个”表单上下文。

你可以说创建一个例程来显示任何形式的城市值,例如:

呼叫 ShowCity(我,“城市”)

然后

Sub ShowCity(f 为表单,strControlToShow 为字符串)

   Msgbox "City value = " & f(strControlToShow)

因此,人们经常会通过简单地选择当前活动表单来编写适用于任何表单的代码:

  Dim f             As Form
  Set f = Screen.ActiveForm

并注意上面的代码是如何立即获取活动表单的——这是一个好主意,因为如果焦点发生变化,“f”引用将保持不变,用于调用“通用”例程中的代码+ 用于多种形式。

但是由于子表单问题,通常最好总是传递“整个”表单实例/对象:

Call MyNewRecord(me)

然后将sub定义为:

Sub MyNewReocord(f as form)

   DoCmd.GoToRecord acDataForm, f.Name, acNewRec

结束子

你可以选择在上面添加“焦点”

f.SetFocus

所以对于很多菜单或功能区代码,你不传递表单对象,而只是使用screen.ActiveForm,你也可以使用Screen.ActiveControl(同样伟大的菜单栏或功能区代码来抓取什么控件有重点)。但是由于子表单的限制,经常将“我”传递给例程会在某些情况下获得类似的结果,如果不是更好的话。

【讨论】:

  • 如果我能通过参考,我不会依赖Screen.ActiveForm。就像ActiveSheetin Excel 一样,它可能会导致意想不到的结果。 DoCmd 也很丑(打开或关闭表单/报告除外)。我更喜欢frm.Recordset.AddNew
  • 我建议将表单引用作为后备位置。然而 screen.Activeform 20 年来一直是 Access 应用程序的“中流砥柱”。菜单栏、工具栏和现在的功能区在您编写的选项或代码中的 BOTH BUILT 中的工作方式完全相同。因此,您必须建议这里的每个人都不要使用 Access 中的任何内置选项!您无法制作坚固的外壳,否则您必须建议不要使用任何功能区选项——即使是内置选项!所以有些谨慎和“怪癖”是有道理的,但作为避免屏幕的“一般”建议。Activeform 不是一般规则,也不是一般建议。
  • 我从来没有这么说!但是,如果我可以对对象使用更可靠的引用,我会使用它。如果我需要Screen.ActiveForm我会使用它,但如果不需要,我更喜欢参考!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
相关资源
最近更新 更多