除非我破坏用户窗体初始化,否则事件处理 class 不会触发

Event handling class doesn't fire unless I break userform initialization

这是对以下问题的跟进:

回顾一下:我们的目标是构建一个带有一些命令按钮和一个包含复选框的框架的表单。复选框在框架中的 userform_initialize 处动态填充,因此用户可以滚动浏览它们。我的问题是键盘快捷键。不可能为每个复选框强行编写 KeyDown 处理程序,因为我不知道哪些会存在。不幸的是,Excel 不支持 KeyPreview 所以我不得不模拟我自己的版本。感谢@UGP 为我提供了看似可行但不太可行的有前途的途径...

首先,这是我的 class 模块,名为 clsReasonPickKP。我为每个复选框创建一个新实例来监听 KeyDown 事件:

Option Explicit

Dim WithEvents vChkBx As MSForms.CheckBox

Friend Sub initializeListener(cControl As control)
Set vChkBx = cControl
End Sub

Private Sub vChkBx_KeyDown(ByVal keyCode As MSForms.ReturnInteger, ByVal shift As Integer)
frm2.keyChooser keyCode
End Sub

frm2.keyChooser keyCode 启动位于用户窗体代码模块中的快速子。代码如下:

Public Sub keyChooser(ByVal keyCode As MSForms.ReturnInteger)
Select Case keyCode
    Case vbKeyEscape: cancelBtn_Click
    Case vbKeyReturn: completeDecision_Click
    Case vbKeyN: customizeNote_Click
    Case vbKeyS: resetDecisionNote_Click
    Case vbKeyR: chkRefGrnds_Click
End Select
End Sub

我已经复制了下面 UserForm_Initialize 部分的相关部分。该循环为每个创建复选框和一个事件侦听器。

Sub UserForm_Initialize()
Dim x As Long, maxWidth as Long
Dim cControl As control
Dim keyPreviewCollection As New Collection
Dim keyPreviewer As clsReasonPickKP
For x = 1 To dTbl.Rows.Count - 1
    Set cControl = chkBoxFrame.Controls.Add("Forms.CheckBox.1", "chkBox" & x, True)
    With cControl
        .AutoSize = True
        .WordWrap = False
        .Left = 10
        .Top = 16 * x - 12
        .Caption = dTbl(x, 1).Value
        If .Width > maxWidth Then maxWidth = .Width
    End With
Set keyPreviewer = New clsReasonPickKP
keyPreviewer.initializeListener cControl
keyPreviewCollection.Add keyPreviewer
Next x
'Additional initialization code here
End Sub

奇怪的是,除非我在 keyPreviewCollection.Add keyPreviewer 之后的某个时间中断代码,否则侦听器似乎不会处理该事件。例如,如果我在 Next xx > 1 处设置一个断点,然后完成初始化,那么当表单完成初始化并出现时,侦听器调用 keyChooser 并且一切正常;如果我不那样破坏代码,它就不会捕获事件或调用子程序等。

为了解决问题,我试过不将 keyPreviewer 添加到集合中,然后监听器也不起作用,无论我是否或何时中断。似乎将对象添加到集合中,并在将其添加到集合后处于代码中断模式,以某种方式使侦听器捕获事件。

同样有趣的是,如果我在 vChkBx_KeyDown 模块中放置一个断点,它会在引发事件时中断(假设如上所述有适当的中断)。然而,在我 运行 代码之后,它在引发 KeyDown 事件时停止处理它。

如果有帮助,我目前在 Excel 2010 年工作。

有人知道发生了什么事吗?知道如何解决这个问题,即使使用不同的代码方法吗?

一如既往地感谢大家的帮助。

原来问题原来这么简单,就在我眼前。我只需要在我的用户表单代码模块中创建 keyPreviewerkeyPreviewCollection 变量 public。

这仍然没有回答为什么在将对象添加到集合后中断代码执行使得 VBA 将其视为 public,但很高兴一切正常。

DoEvents 可能是门票。请参阅以下文章:

https://www.automateexcel.com/vba/doevents/