VBA - 在动态创建的文本框上捕获事件

时间:2015-06-17 18:25:43

标签: excel vba excel-vba events userform

我正在Excel中编写VBA应用程序。我有一个Userform,它根据其中一个工作表中包含的数据动态构建自己。 创建各种组合框,文本框和标签的所有代码都在工作。 我创建了一个类模块来捕获Comboboxes的OnChange事件,并再次按预期工作。 现在我需要为某些文本框捕获OnChange事件,因此我创建了一个新的类模块,用于组合框以捕获事件。

Public WithEvents tbx As MSForms.TextBox

Sub SetTextBox(ctl As MSForms.TextBox)
Set tbx = ctl
End Sub

Public Sub tbx_Change()
Dim LblName As String

MsgBox "You clicked on " & tbx.Name, vbOKOnly

End Sub

消息框只是为了在我走得更远之前确认它有效。 我得到的问题是在UserForm代码模块中:

Dim TBox As TextBox
Dim tbx As c_TextBoxes

'[...]

Set TBox = lbl
Set tbx = New c_TextBoxes
tbx.SetTextBox lbl
pTextBoxes.Add tbx

这会在Set TBox=lbl处引发类型不匹配错误。它是完全相同的代码,适用于ComboBox,只是给出了变量名称的变量。我盯着这看了2个小时。 有人有任何想法吗?谢谢你的任何指示。

编辑 - 这是我遇到问题的完整用户表单模块:

Private Sub AddLines(FrameName As String, PageName As String)
Dim Counter As Integer, Column As Integer
Dim obj As Object
Dim CBox As ComboBox
Dim cbx As c_ComboBox
Dim TBox As TextBox
Dim tbx As c_TextBoxes
Dim lbl As Control

Set obj = Me.MultiPage1.Pages(PageName).Controls(FrameName)
If pComboBoxes Is Nothing Then Set pComboBoxes = New Collection
If pTextBoxes Is Nothing Then Set pTextBoxes = New Collection

For Counter = LBound(Vehicles) To UBound(Vehicles)
     For Column = 1 To 8
     Select Case Column
     Case 1
         Set lbl = obj.Add("Forms.Label.1", "LblMachine" & FrameName & Counter, True)
    Case 2
        Set lbl = obj.Add("Forms.Label.1", "LblFleetNo" & FrameName & Counter, True)
    Case 3
        Set lbl = obj.Add("Forms.Label.1", "LblRate" & FrameName & Counter, True)
    Case 4
        Set lbl = obj.Add("Forms.Label.1", "LblUnit" & FrameName & Counter, True)
    Case 5
        Set lbl = obj.Add("Forms.ComboBox.1", "CBDriver" & FrameName & Counter, True)
    Case 6
        Set lbl = obj.Add("Forms.Label.1", "LblDriverRate" & FrameName & Counter, True)
    Case 7
        Set lbltbx = obj.Add("Forms.TextBox.1", "TBBookHours" & FrameName & Counter, True)
    Case 8
        Set lbl = obj.Add("Forms.Label.1", "LblCost" & FrameName & Counter, True)
    End Select
    With lbl
        Select Case Column
        Case 1
            .Left = 1
            .Width = 60
            .Top = 10 + (Counter) * 20
            .Caption = Vehicles(Counter).VType
        Case 2
            .Left = 65
            .Width = 40
            .Top = 10 + (Counter) * 20
            .Caption = Vehicles(Counter).VFleetNo
        Case 3
            .Left = 119
            .Width = 50
            .Top = 10 + (Counter) * 20
            .Caption = Vehicles(Counter).VRate
        Case 4
            .Left = 163
            .Width = 30
            .Top = 10 + (Counter) * 20
            .Caption = Vehicles(Counter).VUnit
        Case 5
            .Left = 197
            .Width = 130
            .Top = 10 + (Counter) * 20
            Set CBox = lbl 'WORKS OK
            Call CBDriver_Fill(Counter, CBox)
            Set cbx = New c_ComboBox
            cbx.SetCombobox CBox
            pComboBoxes.Add cbx
        Case 6
            .Left = 331
            .Width = 30
            .Top = 10 + (Counter) * 20
        Case 7
            .Left = 365
            .Width = 30
            .Top = 10 + (Counter) * 20
            Set TBox = lbl 'Results in Type Mismatch
            Set tbx = New c_TextBoxes
            tbx.SetTextBox TBox
            pTextBoxes.Add tbx
        Case 8
            .Left = 400
            .Width = 30
            .Top = 10 + (Counter) * 20
        End Select
    End With
    Next
Next
obj.ScrollHeight = (Counter * 20) + 20
obj.ScrollBars = 2

End Sub

这是c_Combobox类模块:

Public WithEvents cbx As MSForms.ComboBox

Sub SetCombobox(ctl As MSForms.ComboBox)
    Set cbx = ctl
End Sub

Public Sub cbx_Change()
Dim LblName As String
Dim LblDriverRate As Control
Dim i As Integer


    'MsgBox "You clicked on " & cbx.Name, vbOKOnly
    LblName = "LblDriverRate" & Right(cbx.Name, Len(cbx.Name) - 8)
    'MsgBox "This is " & LblName, vbOKOnly

    'Set obj = Me.MultiPage1.Pages(PageName).Controls(FrameName)
    Set LblDriverRate = UFBookMachines.Controls(LblName)
    For i = LBound(Drivers) To UBound(Drivers)
        If Drivers(i).Name = cbx.Value Then LblDriverRate.Caption = Drivers(i).Rate
    Next
End Sub

最后,这是c_TextBoxes类模块:

Public WithEvents tbx As MSForms.TextBox

Sub SetTextBox(ctl As MSForms.TextBox)
    Set tbx = ctl
End Sub

Public Sub tbx_Change()
Dim LblName As String
    'Does nothing useful yet, message box for testing
    MsgBox "You clicked on " & tbx.Name, vbOKOnly

End Sub

1 个答案:

答案 0 :(得分:0)

经过一些快速测试后,如果我声明"main": [ "highcharts.js", "highcharts-more.js", "modules/exporting.js", "modules/funnel.js" ] ,我就能重现您的错误。如果我声明TBox as TextBox,我不会收到错误。我建议您使用TBox as MSForms.TextBox限定符声明所有TextBox个变量。

测试代码与您的相似。我有MSForms MultiPage我在其中添加了Frame

Control

我不确定为什么Private Sub CommandButton1_Click() Dim obj As Object Set obj = Me.MultiPage1.Pages(0).Controls("Frame1") Dim lbl As Control Set lbl = obj.Add("Forms.TextBox.1", "txt", True) If TypeOf lbl Is TextBox Then Debug.Print "textbox found1" 'does not execute End If If TypeOf lbl Is MSForms.TextBox Then Debug.Print "textbox found2" Dim txt1 As MSForms.TextBox Set txt1 = lbl 'no error End If If TypeOf lbl Is MSForms.TextBox Then Debug.Print "textbox found3" Dim txt As TextBox Set txt = lbl 'throws an error End If End Sub 而不是TextBox需要限定词。正如您在上面所看到的,对此进行的一个很好的测试是ComboBox来测试哪些对象是哪种类型。我添加了第一个块来显示If TypeOf ... Is ... Then不是“裸”lbl,但是,我再也不知道为什么会这样。也许还有另一种TextBox覆盖了默认声明?