创建一个类来处理访问表单控制事件

Posted

技术标签:

【中文标题】创建一个类来处理访问表单控制事件【英文标题】:Creating a Class to Handle Access Form Control Events 【发布时间】:2014-05-07 15:37:10 【问题描述】:

我正在尝试创建一个类来处理 Access 中的多个控制事件。这是为了避免重复输入多行相同的代码。

我已经按照下一页上的答案进行了操作,但进行了一些调整以使其适应 Access 而不是 Excel。

How to assign a common procedure for multiple buttons?

我的班级代码如下:

Option Compare Database

Public WithEvents ct As Access.CommandButton 'Changed object type to something recognised by Access

Public Sub ct_Click()
    MsgBox ct.Name & " clicked!"
End Sub

我的表单代码如下:

Option Compare Database
Private listenerCollection As New Collection
Private Sub Form_Load()
Dim ctItem
Dim listener As clListener

For Each ctItem In Me.Controls
    If ctItem.ControlType = acCommandButton Then 'Changed to test whether control is a Command Button
        Set listener = New clListener
        Set listener.ct = ctItem
        listenerCollection.Add listener
    End If
Next

End Sub

我已经在 cmets 中注意到我对(工作的)Excel 代码进行了更改。我认为问题出在类中的对象声明上。注意:在此过程中不会抛出任何错误;它根本不会触发事件。

提前致谢!

编辑:

我已经将问题缩小到在“点击”事件中没有“[事件过程]”。如果我手动添加它,该类将按预期工作。显然,我不想手动添加这些 - 它会破坏对象。有什么想法我会怎么做?

【问题讨论】:

我前段时间做过类似的事情,所以不记得所有细节了。以下链接很有帮助。 support.microsoft.com/?kbid=234907您的班级需要一个属性“表格”。在属性集中,添加代码 . = "[Event Procedure]" 在表单的模块级别声明类 Private mclass 为 在 form_open 事件中 Set mclass= New mclass .Form = 我 【参考方案1】:

在您的 OnLoad 事件中,您可以添加此行

Dim ctItem
Dim listener As clListener

For Each ctItem In Me.Controls
    If ctItem.ControlType = acCommandButton Then 'Changed to test whether control is a Command Button
        Set listener = New clListener
        Set listener.ct = ctItem
        listener.ct.OnClick = "[Event Procedure]"  '<------- Assigned the event handler
        listenerCollection.Add listener
    End If
Next

虽然我不确定这是否比在设计器中双击 OnClick 并粘贴方法调用更多代码。不管怎样都很酷。

编辑: 你可以像这样改变你的班级

Public WithEvents ct As Access.CommandButton 'Changed object type to something recognised by Access

Public Function AddControl(ctrl as Access.CommandButton) as Access.CommandButton
    set ct = ctrl
    ct.OnClick = "[Event Procedure]"
    Set AddControl = ct
End Function

Public Sub ct_Click()
    MsgBox ct.Name & " clicked!"
End Sub

然后你可以在你的表单中添加这样的 ct

For Each ctItem In Me.Controls
    If ctItem.ControlType = acCommandButton Then 'Changed to test whether control is a Command Button
        Set listener = New clListener
        listener.AddControl ctItem
        listenerCollection.Add listener
    End If
Next

现在事件处理程序已添加到类中。

【讨论】:

谢谢布拉德,我实际上已经走这条路了,但我更愿意在课堂上设置属性 - 我将尝试上面 AVG 的建议。 +1 用于提供可行的解决方案。 @JiminyCricket 我做了一个编辑,让你可以在类中进行所有属性设置 这非常有帮助!我一直试图在课堂上获得一个属性,我什至从未考虑过取消一个函数。尽管在加载期间添加属性可以正常工作,但这要好得多,因为它都是自包含的。于是我的课堂冒险开始了……我想进入很长时间的事情!【参考方案2】:

使用类模块处理访问表单控件输入的通用方法:

此代码旨在处理在弹出窗口中编写的应用程序。主窗体包含一个选项卡控件,其中每个选项卡都包含其自己的子窗体,指向链接的子表或独立表。使用或不使用选项卡控件不应对类模块处理产生任何影响。

可以修剪代码以满足您的应用程序的需要。例如,可以从类模块中删除不使用的控件。同样,控件集合子例程可以通过使用 TypeName(Ctl) 语句来筛选添加到集合中的控件来进行选择。

在名为 clsMultipleControls 的类模块中放入以下代码。

Option Compare Database
Option Explicit

Private m_PassedControl As Control

Private WithEvents atch As Attachment
Private WithEvents bfrm As BoundObjectFrame
Private WithEvents chk As CheckBox
Private WithEvents cbo As ComboBox
Private WithEvents btn As CommandButton
Private WithEvents cctl As CustomControl
Private WithEvents img As Image
Private WithEvents lbl As Label
Private WithEvents lin As Line
Private WithEvents Lst As ListBox
Private WithEvents frm As ObjectFrame
Private WithEvents optb As OptionButton
Private WithEvents optg As OptionGroup
Private WithEvents pg As Page
Private WithEvents pgb As PageBreak
Private WithEvents Rec As Rectangle
Private WithEvents sfm As SubForm
Private WithEvents tctl As TabControl
Private WithEvents txt As TextBox
Private WithEvents tgl As ToggleButton

Property Set ctl(PassedControl As Control)
Set m_PassedControl = PassedControl

Select Case TypeName(PassedControl)
Case "Attachment"
    Set atch = PassedControl
Case "BoundObjectFrame"
    Set bfrm = PassedControl
Case "CheckBox"
    Set chk = PassedControl
Case "ComboBox"
    Set cbo = PassedControl
Case "CommandButton"
    Set btn = PassedControl
Case "CustomControl"
    Set cctl = PassedControl
Case "Image"
    Set img = PassedControl
Case "Label"
    Set lbl = PassedControl
Case "Line"
    Set lin = PassedControl
Case "ListBox"
    Set Lst = PassedControl
Case "ObjectFrame"
    Set frm = PassedControl
Case "OptionButton"
    Set optb = PassedControl
Case "OptionGroup"
    Set optg = PassedControl
Case "Page"
    Set pg = PassedControl
Case "PageBreak"
    Set pgb = PassedControl
Case "Rectangle"
    Set Rec = PassedControl
Case "SubForm"
    Set sfm = PassedControl
Case "TabControl"
    Set tctl = PassedControl
Case "TextBox"
    Set txt = PassedControl
Case "ToggleButton"
    Set tgl = PassedControl
End Select

End Property

在主窗体模块的顶部放置以下代码。

Public collControls As Collection
Public cMultipleControls As clsMultipleControls

在主窗体的 Load 事件中放置以下代码。

GetCollection Me

在主窗体代码的底部放置以下递归公共子例程:

Public Sub GetCollection(frm As Form)
    Dim ctl As Control

    On Error Resume Next
    Set collControls = collControls
    On Error GoTo 0

    If collControls Is Nothing Then
        Set collControls = New Collection
    End If

    For Each ctl In frm.Controls
        If ctl.ControlType = acSubform Then
            GetCollection ctl.Form
        Else
            Set cMultipleControls = New clsMultipleControls
            Set cMultipleControls.ctl = ctl
            collControls.Add cMultipleControls
        End If
    Next ctl

end sub

我建议给表单及其子表单中的每个控件一个唯一的名称,以便您可以轻松地利用基于控件名称的 Select 语句来实现每个类模块事件中的处理控制。例如,每个文本框更改事件都将发送到类模​​块中的 txt_change 事件,您可以在其中使用 select 语句中的 m_PassedControl.name 属性来指示将在传递的控件上执行哪些代码。

如果您有多个控件将接收相同的 post entry 处理,则 select 事件非常有用。

我使用 Main Form Load 事件而不是 Activate 事件,因为弹出式表单(及其子表单)不会触发 Activate 或 Deactivate 事件。

如果您需要处理一些冗长的处理,也可以将 m_PassedControl 传递给常规模块中的子例程。

不幸的是,除非您在 VBA 模块中实际设置了事件,否则 Access 不会自动触发 VBA 事件。因此,如果您想使用文本框更改事件,您必须确保在适用的 vba 模块中实际设置了文本框更改事件。您不需要向事件添加任何代码,但空事件必须存在,否则事件及其等效类模块将不会触发。如果有人知道解决此问题的方法,我会很高兴听到。

我在http://yoursumbuddy.com/userform-event-class-multiple-control-types/ 的 Excel 用户表单代码示例中找到了这个基本的类模块结构。这是一个灵活的结构。我已经创建了适用于 Excel 用户表单、带有 activex 控件的 Excel 工作表以及现在适用于 Access 表单的版本。

后续注意:上面的代码在 64 位 Windows 10 上与 64 位 Access 2013 一起工作正常。但是当您尝试关闭主窗体时,它在 64 位 Windows 7 上的 64 位 Access 2013 上失败。解决方案是将以下代码从主窗体移动到 VBA 模块。

Public collControls As Collection
Public cMultipleControls As clsMultipleControls

【讨论】:

以上是关于创建一个类来处理访问表单控制事件的主要内容,如果未能解决你的问题,请参考以下文章

访问 2016 表单按钮以根据当前记录打开报告

MS 访问事件加载表单

JQ库函数记忆要点

如何在表单提交到下一个控制器时发送和访问参数/值

如何从控制器内的事件访问范围?

通过表单事件过程中的函数填充访问文本框