我有一个用户表单(
form_Updaterow
),将一些脚本放在一起,以便在单击文本框时在标签中显示附加信息。
当我按 F5 运行用户表单时,它可以工作。当我使用
.Show
(从另一个表单或从宏)打开表单时,脚本不起作用。 跑步和展示可以带来不同的结果吗?
这就是我(理论上)正在做的事情:
1.在表单的(
form_Updaterow
)中,我在初始化表单时为文本框定义了一个新集合。 (我添加了一个 MsgBox 以确认它运行此代码。)
Dim tbCollection As Collection
Dim cbCollection As Collection
Private Sub UserForm_Initialize()
MsgBox ("UserForm initialized")
Sheets("DES").Activate
Dim ctrl As MSForms.Control
Dim obj_tb As clsTextBox
Set tbCollection = New Collection
For Each ctrl In Me.Controls
If TypeOf ctrl Is MSForms.TextBox Then
Set obj_tb = New clsTextBox
Set obj_tb.Control = ctrl
tbCollection.Add obj_tb
End If
Next ctrl
Set obj_tb = Nothing
End Sub
2.在类模块中(
clsTextBox
):
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
'MsgBox ("TextBox property set")
Set MyTextBox = tb
End Property
Private Sub MyTextBox_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'MsgBox ("Call the provider")
Call TheInfoProvider
End Sub
3.在模块 (
mod_Infos
) 中,我循环遍历文本框并识别已单击的文本框。 (因为某些文本框位于框架中,所以我必须添加 activename() 函数。否则我无法使其工作)。然后,我使用文本框的名称 ('txt_VARNAME') 来识别表中的指导文本 (DatDic_DES
)。
Public Sub TheInfoProvider()
'MsgBox ("I'm the Info Provider")
For Each c In form_Updaterow.Controls
If TypeName(c) = "TextBox" Or TypeName(c) = "ComboBox" Then
MsgBox activename
If c.Name = activename() Then
varname = Split(c.Name, "_", 2)(1)
Set DatDic = Worksheets("Data Dictionary").ListObjects("DatDic_DES")
varnames = DatDic.ListColumns("Variable Name").Range
tabrow = Application.Match(varname, varnames, 0)
form_Updaterow.fr_varname.Visible = True
form_Updaterow.lbl_varname.Caption = varname
guidance = DatDic.ListColumns("Guidance").Range.Cells(tabrow)
form_Updaterow.lbl_guidance.Caption = guidance
End If
End If
Next c
End Sub
Public Function activename() As String 'MSForms.Control
Set ReallyActiveControl = form_Updaterow.ActiveControl
On Error Resume Next
Set ReallyActiveControl = ReallyActiveControl.ActiveControl
activename = ReallyActiveControl.Name
End Function
当我使用 F5 运行表单 (
form_Updaterow
) 时,代码有效:我收到“UserForm 已初始化”消息,然后弹出一个包含单击文本框名称的窗口(多次,每个文本框一次)我的表格)。结果是标签 (lbl_guidance
) 现在已更改为该文本框的指导文本。
但是,当我使用
.Show
加载表单时,例如使用下面的宏(也是当我从另一个表单加载时): 在显示表单之前,我收到“UserForm 已初始化”消息(到目前为止,一切都很好)。然后,当我单击文本框时,我再次收到相同的消息,然后是多个空消息框。
Public Sub Main()
Dim frm As New form_Updaterow
frm.Show vbModel
Set frm = Nothing
End Sub
问题似乎出在识别 ActiveControl 上。
故障排除之所以如此具有挑战性,是因为当我按 F5 运行表单时和使用宏(或另一个用户表单中的按钮)
.Show
表单时,行为是不同的。我认为这将有助于理解加载表单的一种方式和另一种方式之间的根本区别。
我在 Office 365 版本 2408(内部版本 17928.20156 即点即用)和 VBA 7.1.1143 上使用 Excel
感谢@TimWilliams 提供了最初问题的解决方案。无需调用
TheInfoProvider
并让它使用循环查找选定的 TextBox,而是直接将 TextBox 传递给它解决了该问题。不过,在更新指导标签时出现了另一个问题,在 @TimWilliams 建议使用 .Parent
(对框架中的文本框进行一些调整)后,这个问题得到了解决。
这是新的、完全有效的代码:
在
clsTextBox
课程模块中
Private Sub MyTextBox_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
TheInfoProvider MyTextBox
End Sub
在
mod_Infos
模块中(我注释掉了旧代码以显示差异)
Public Sub TheInfoProvider(c)
'MsgBox ("I'm the Info Provider")
' For Each c In form_Updaterow.Controls
'
' If TypeName(c) = "TextBox" Or TypeName(c) = "ComboBox" Then
' MsgBox cargo.Name
' If c.Name = cargo.Name Then
Dim ancestry As Object
Set ancestry = c.Parent
If c.Parent.Name <> "form_Updaterow" Then
Set ancestry = c.Parent.Parent
End If
varname = Split(c.Name, "_", 2)(1)
Set DatDic = Worksheets("Data Dictionary").ListObjects("DatDic_DES")
varnames = DatDic.ListColumns("Variable Name").Range
tabrow = Application.Match(varname, varnames, 0)
ancestry.fr_varname.Visible = True
ancestry.lbl_varname.Caption = varname
guidance = DatDic.ListColumns("Guidance").Range.Cells(tabrow)
ancestry.lbl_guidance.Caption = guidance
' End If
'
' End If
' Next c
End Sub
非常感谢您帮我解决这个问题!