单击事件不适用于以编程方式/动态创建的选项按钮 [英] click event not working on programmatically / dynamically created optionbutton

查看:20
本文介绍了单击事件不适用于以编程方式/动态创建的选项按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码以编程方式/动态创建一个框架并添加一个选项按钮:

I have the following code that programmatically / dynamically creates a frame and adds an option button:

Private Sub ComboBox1_Change()

    Dim cb1234Frame As MsForms.Frame
    Dim opbtn1 As MsForms.OptionButton

    Set cb1234Frame = RT_Graph_Form.Controls.Add("Forms.Frame.1")

    With cb1234Frame
        .Top = 132
        .Left = 12
        .Height = 30
        .Width = 144
        .Caption = "Number of Graphs to Display"
    End With

    Set opbtn1 = cb1234Frame.Controls.Add("Forms.OptionButton.1")

    With opbtn1
        .Top = 6
        .Left = 6
        .Height = 18
        .Width = 21.75
        .Caption = "1"
    End With

End Sub

但这不起作用:

Private Sub opbtn1_Click()

    MsgBox "Test Successful!!"

End Sub

推荐答案

问题是事件处理程序需要在编译时绑定:不能为动态创建的控件创建事件处理程序.

The problem is that event handlers need to be bound at compile-time: you cannot create an event handler for a dynamically created control.

向您的项目添加一个新的类模块,将其命名为DynamicOptionButton.该类的作用是包装 MSForms 控件并对其进行编译时引用:

Add a new class module to your project, call it DynamicOptionButton. The role of this class is to wrap the MSForms control and have a compile-time reference to it:

Option Explicit
Private WithEvents Wrapper As MSForms.OptionButton

Public Sub Initialize(ByVal ctrl As MSForms.OptionButton)
    Set Wrapper = ctrl
End Sub

Private Sub Wrapper_Click()
    MsgBox "Works!"
End Sub

请注意,只有一部分事件可以处理:哪些事件可用,取决于您声明包装器引用的接口 - MSForms.Control 有许多事件(和属性),MSForms.OptionButton 有另一组:您可能需要声明两个接口(即同一对象的 2 个包装器)才能访问所有成员.

Note that only a subset of the events will be available to handle: what events are available, depend on the interface you're declaring the wrapper reference with - MSForms.Control has a number of events (and properties), MSForms.OptionButton has another set: you may need to declare both interfaces (i.e. 2 wrappers for the same object) in order to access all the members.

现在在表单的 declarations 部分中,您需要保存对所有包装器的引用,否则对象将超出范围,处理程序将无法工作.Collection 可以做到这一点:

Now in your form's declarations section, you'll need to hold a reference to all wrappers, otherwise the objects just fall out of scope and the handlers won't work. A Collection can do that:

Option Explicit
Private ControlWrappers As Collection

Private Sub UserForm_Initialize()
    Set ControlWrappers = New Collection
End Sub

'...

Private Sub CreateOptionButton()
    Dim ctrl As MSForms.OptionButton
    Set ctrl = Me.Controls.Add("Forms.OptionButton.1")
    'set properties...

    Dim wrap As DynamicOptionButton
    Set wrap = New DynamicOptionButton
    wrap.Initialize ctrl

    ControlWrappers.Add wrap
End Sub

注意不要在表单自己的代码隐藏中引用表单的类名:全局范围的 RT_Graph_Form 标识符指的是 VBA 控制的默认实例"自动实例化对象,该对象可能或可能不是正在显示的实际表单实例.您想将动态控件添加到 Me.Controls,而不是 RT_Graph_Form.Controls.

Be careful to never reference the form's class name in the form's own code-behind: the global-scope RT_Graph_Form identifier refers to a VBA-controlled "default instance" auto-instantiated object that may or may not be the actual form instance that's being shown. You want to add your dynamic controls to Me.Controls, not RT_Graph_Form.Controls.

现在,我们可以处理在运行时产生的控件事件,但还有另一个问题:DynamicOptionButton 类中的事件处理程序没有引用它所在的窗体!

Now, we can handle events of controls spawned at run-time, but there's another problem: the event handler in the DynamicOptionButton class has no reference to the form it's on!

是吗?

每个 MSForms 控件都有一个 Parent 属性;您可以通过递归地向上 Parent 属性直到返回的引用是 UserForm 来获取父 UserForm - 然后您可以从那里访问公开曝光的所有内容.

Every MSForms control has a Parent property; you can get ahold of the parent UserForm by recursively going up the Parent property until the returned reference is a UserForm - and from there you can access everything that's publicly exposed.

这篇关于单击事件不适用于以编程方式/动态创建的选项按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆