VBA – 在dynamic创build的文本框上捕获事件

我正在Excel中编写一个VBA应用程序。 我有一个用户窗体,根据其中一个工作表中包含的数据dynamic构build自己。 所有创build各种combobox,文本框和标签的代码正在工作。 我创build了一个类模块来捕获combobox的OnChange事件,并且按预期工作。 现在我需要为某些文本框捕获OnChange事件,所以我创build了一个新的类模块,用于combobox捕获事件。

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 

这会引发一个types不匹配错误在Set TBox=lbl 。 这是完全相同的代码,工作正常的ComboBox,只是与variables给定的approriate名称。 我盯着这个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 

经过一些快速testing,如果我将TBox as TextBox声明TBox as TextBox ,我能够重现您的错误。 如果我将TBox as MSForms.TextBox声明TBox as MSForms.TextBox则不会出现错误。 我会build议使用MSForms限定符声明所有的TextBoxvariables。

testing代码与您的相似。 我有一个MultiPageFrame ,我添加一个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 。 正如你在上面看到的,一个好的testing是If TypeOf ... Is ... Thentesting哪些对象是哪个types。 我包括第一块显示lbl不是一个“光秃秃的” TextBox ,但是,我再也不知道这是为什么。 也许有另一种types的TextBox ,覆盖默认声明?