【问题标题】:VBA button event handler implementationVBA 按钮事件处理程序实现
【发布时间】:2019-03-15 18:40:50
【问题描述】:

我想使用以下类代码处理类中对 CommandButton 的点击

Option Explicit

Private m_First                     As MSForms.CommandButton
Private WithEvents evFirst          As MSForms.CommandButton

Property Get First() As MSForms.CommandButton
    Set First = m_First
End Property
Property Let First(ByRef o As MSForms.CommandButton)
    Set m_First = o
    Set evFirst = o
End Property

Private Sub evFirst_Click()
    MsgBox "It Worked!"
End Sub

除了它不起作用之外,我想知道为什么表单中按钮的引用与类中的不同,即:

Sub Tester()
    Dim f As New UserForm1
    Dim o As New cButtonClass
    o.First = f.CommandButton1

    Dim k1 As LongLong: k1 = ObjPtr(o.First)
    Dim k2 As LongLong: k2 = ObjPtr(f.CommandButton1)
    Debug.Assert k1 = k2 'NOPE!
End Sub

为什么这不起作用?解决方法是什么?

【问题讨论】:

  • 我看到了 2 个问题。首先,在您的班级中将Property Let 更改为Property Set。其次,在表单代码中你需要说Set o.First。可能还有其他问题。
  • 另外,evFirst 对象与m_First 对象相同。 WithEvents 关键字只允许您为声明 WithEvents 的对象编写自定义代码。本质上,您不需要那个 m_First 变量....
  • 这不是编码风格的事情。这是关于满足期望。此外,如果你的类有一个默认成员,那么 let-coercion 将使用相同的代码从字面上改变该成员的工作方式——这在客观上是错误的,根本不是风格问题。一个是正​​确的,另一个是乞求未来的错误发生。
  • @Berryl - ObjPtr 在包裹在 Variant 中后不可靠。在这种情况下,您需要使用 VarPtrDebug.Assert VarPtr(o.First) = VarPtr(f.CommandButton1) 应该通过。
  • 取决于您要测试的内容。如果您正在测试表单,因为那是您的逻辑所在,那么您有一个设计问题(智能 UI [反] 模式)并且需要重构为更类似于 MVP 的解决方案。我不为视图级逻辑编写单元测试,所以我的单行答案是“你不会”。你将如何在 C# 中做同样的事情?你不会,因为你不会让表单在 C# 中运行显示 - 所以,在 VBA 中做同样的事情! (我的博客上有几篇关于此的文章)

标签: excel vba


【解决方案1】:

这里是反映上述 cmets 的更新代码。它按预期工作。但是,对于您关于ObjPtr 的其他问题,我还没有答案。

这是课程代码:

Option Explicit

Private WithEvents evFirst As MSForms.CommandButton

Property Get First() As MSForms.CommandButton
    Set First = evFirst
End Property

Property Set First(ByRef o As MSForms.CommandButton)
    Set evFirst = o
End Property

Private Sub evFirst_Click()
    MsgBox "Class Click"
End Sub

这是工作表代码:

Option Explicit

Public Sub Tester()
    Dim f As UserForm1
    Dim o As cButtonClass

    Set f = New UserForm1
    Set o = New cButtonClass
    Set o.First = f.CommandButton1
    f.Show vbModal

    Dim k1 As LongPtr: k1 = ObjPtr(o.First)
    Dim k2 As LongPtr: k2 = ObjPtr(f.CommandButton1)
    Debug.Assert k1 = k2 'NOPE!
End Sub

这是用户表单代码:

Private Sub CommandButton1_Click()
   MsgBox "UserForm Click"
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 2020-05-09
    • 1970-01-01
    • 2012-08-17
    相关资源
    最近更新 更多