【问题标题】:Click Event in Class Module Not Firing类模块中的单击事件未触发
【发布时间】:2018-04-20 03:27:46
【问题描述】:

我有一个显示逐行验证错误的用户表单(在文本框中),我想用用户表单标签作为超链接来补充它,用户可以单击这些标签直接转到有问题的单元格。

我有动态构建标签的代码,并通过类模块添加了一个点击事件,但我无法让它触发类模块中的点击事件。

我确实从构建这种类型的标签和点击事件的工作代码修改了这段代码,但是该代码在用户窗体初始化时加载标签并将每个类对象放入一个集合中。我不知道这是否需要构建到我的解决方案中,但我玩过它但无法让它工作。

如果需要,这是我在用户窗体上放置标签的过程。如果需要验证,它会在另一个过程中运行。如果需要验证,则显示用户表单,并填写消息(以及现在创建的这个标签)。

Sub PlaceLinkLabel(SayWhat As String, WhichSheet As String, WhichRange As String)

    Dim lblNew As MSForms.Label
    Set lblNew = frmValidationMessage.Controls.Add(bstrProgID:="Forms.Label.1", Name:=SayWhat, Visible:=True)

    With lblNew
        With .Font
            .Size = 10
            .Name = "Comic Sans MS"
        End With

        .Caption = SayWhat
        .Top = 55
        .Height = 15
        .Left = 465
        .Width = 100
    End With

    Dim clsLabel As UserFormLabelLinks
    Set clsLabel = New UserFormLabelLinks
    Set clsLabel.lbl = lblNew

    With clsLabel
        .WhichRange = WhichRange
        .WhichSheet = WhichSheet
    End With

    'not sure if this is needed or not
    'Dim pLabels As Collection
    'Set pLabels = New Collection
    'pLabels.Add clsLabel

End Sub

这里是UserFormLabelLinks类模块:

Option Explicit

Private WithEvents pLabel As MSForms.Label
Private sWhichRange As String
Private sWhichSheet As String

Public Property Set lbl(value As MSForms.Label)
    Set pLabel = value
End Property

Public Property Get WhichSheet() As String
    WhichSheet = sWhichSheet
End Property

Public Property Let WhichSheet(value As String)
    sWhichSheet = value
End Property

Public Property Get WhichRange() As String
    WhichRange = sWhichRange
End Property

Public Property Let WhichRange(value As String)
    sWhichRange = value
End Property


Private Sub pLabel_Click()

    MsgBox "hi" 'when i click label, this does not fire

    'Application.Goto ThisWorkbook.Worksheets(WhichSheet).Range(WhichRange), True
    'ActiveWorkbook.FollowHyperlink ("#" & WhichSheet & "!" & WhichRange)

End Sub

【问题讨论】:

标签: vba excel class events


【解决方案1】:

另一种有效的方法:

放置 Private pLabels As Collection 位于存储 PlaceLinkLabel 的模块顶部

并使用

If pLabels Is Nothing Then Set pLabels = New Collection
pLabels.Add clsLabel

PlaceLinkLabel 模块的末尾

【讨论】:

  • 已投赞成票,但收藏 Public 对我来说似乎“危险”!
  • 是的,好点。因为另一个过程模块可能会意外访问该集合正确吗?
  • SetNothing,或者Clear 它,或者做一些不应该做的事情。并不是说任何理智的开发人员都会这样做,但为什么一开始就允许这样做呢?
  • @Mat'sMug - 有趣的是,当我使用您的方法并添加多个标签时,只有最后一个添加的标签会触发代码。当我使用收集方法时,所有标签都会触发代码,这实际上非常有意义。更多为可能偶然发现此问题并可能被添加多个标签的其他人发表此评论。
【解决方案2】:

MSForms.Label 对象一旦退出,PlaceLinkLabel 就会超出范围,UserFormLabelLinks 对象引用也是如此;因此您正在创建一个标签,但它是一个即发即弃的东西,一旦达到End Sub,您就无法以编程方式访问它,因此事件永远不会触发。

您需要一个私有字段来保存 UserFormLabelLinks 对象引用(从而通过封装的 pLabel 字段保留 MSForms.Label 引用):

Option Explicit
Private clsLabel As UserFormLabelLinks

然后在程序中删除这一行:

Dim clsLabel As UserFormLabelLinks

换句话说,将该局部变量提升为一个字段,以便在过程完成后保留它。

【讨论】:

  • 我知道你会在这个之上。非常感谢。在我发布问题后,我还找到了另一种通过收集使其工作的方法。我也会抛出这个答案,仅供参考。
  • 是的。将引用存储在模块级集合中也会保留它。这个想法只是为了让对象引用比过程更长寿 =)
  • 是的。一旦我发布问题并再次查看代码,我立即理解了问题(保持对象周围)。这就像问问题提供了答案 - 这在生活中经常发生。
  • #Rubberducked =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多