dr(没有间接细节):我试图引用在另一个模块中以编程方式创建的控件,但它正在抛出
"编译错误:未定义变量。"
这是我尝试做的事情(也许我的方法完全错了,如果是这样,请告诉我):我正在尝试创建一个使用列表框作为菜单的用户表单用户可以在其中选择项目并查看与该项目相关的控件(标签,文本框)。例如:item" General Information"提交者姓名,部门,日期等; item"报告请求"将有报告申请,所需的应用程序名称等。选择"一般信息"在列表框上应该.visible = true框架包含" GI"控制和隐藏其他框架,并选择"报告请求" item will .visible = false General Information frame but .visible = true Report Request frame,依此类推。
因为我希望将控件放在userform上的相同位置,所以我在Construct模块中以编程方式创建它们。它看起来像这样:
Public Sub GeneralInformationCreator()
Dim i As Integer
Dim labelGeneral As MSForms.Label
Dim frameGeneral As MSForms.Frame
Dim frameRequestInformation As MSForms.Frame
Dim frameSubmitterInformation As MSForms.Frame
Dim labelAppSelect As MSForms.Label
Dim listAppSelect As MSForms.ListBox
Dim labelDateSelect As MSForms.Label
Dim comboMonthSelect, comboDaySelect, comboYearSelect As MSForms.ComboBox
Dim labelSubmitterFName, labelSubmitterLName As MSForms.Label
Dim inputSubmitterFName, inputSubmitterLName As MSForms.TextBox
Dim labelSponsorFName, labelSponsorLName As MSForms.Label
Dim inputSponsorFName, inputSponsorLName As MSForms.TextBox
Dim labelDepartmentName As MSForms.Label
Dim inputDepartmentName As MSForms.TextBox
Set labelGeneral = formRequestWizard.Controls.Add("Forms.Label.1", "labelGeneral", True)
With labelGeneral
.Font.Size = 12
.Top = 12
.Left = 192
.Height = 14.25
.Width = 42
.Caption = "General Information"
.Name = labelGeneral
End With
Set frameGeneral = formRequestWizard.Controls.Add("Forms.Frame.1", "frameGeneral", True)
With frameGeneral
.Top = 30
.Left = 192
.Height = 310
.Width = 384
.Caption = ""
.BorderColor = RGB(255, 255, 255)
Set frameRequestInformation = frameGeneral.Controls.Add("Forms.Frame.1", "frameRequestInformation", True)
With frameRequestInformation
.Top = 15
.Left = 15
.Height = 100
.Width = 350
.Caption = "Request Information"
.BorderStyle = 1
.BorderColor = RGB(0, 0, 0)
Set labelAppSelect = frameRequestInformation.Controls.Add("Forms.Label.1", "labelAppSelect", True)
With labelAppSelect
.Caption = "Select an application:"
.Top = 15
.Left = 15
.Width = 100
.Height = 20
.AutoSize = True
End With
使用UserForm_Initialize()在运行时调用Construct方法,如下所示:
Private Sub UserForm_Initialize()
Call Construct.GeneralInformationCreator
Call Construct.ApplicationDetailsCreator
With formRequestWizard.listMenu
.AddItem ("General Information")
.AddItem ("Application Details")
'.Selected(0) = True
End With
End Sub
以下是问题:在userform代码中,我有一个listMenu_Change(),如下所示:
Private Sub listMenu_Change()
If (listMenu.Selected(0) = True) Then
labelGeneral.Visible = True
frameGeneral.Visible = True
Else
labelGeneral.Visible = False
frameGeneral.Visible = False
End If
If (listMenu.Selected(1) = True) Then
labelAppDetails.Visible = True
frameAppDetails.Visible = True
Else
labelAppDetails.Visible = False
frameAppDetails.Visible = False
End If
End Sub
从列表框中选择一个项会从tl中引发错误; dr:"编译错误:变量未定义"在第一个变量" labelGeneral"。
我已经尝试将所有脚本放入userform代码窗口,并将控件Dims放在Subs之外。我所做的研究主要是讨论如何为运行时创建的控件创建事件处理程序,但我决定通过对象视图放置listMenu对象,所以我不确定& #39;适用。
答案 0 :(得分:3)
定义所有变量:
Dim comboMonthSelect As MSForms.Combobox
Dim comboDaySelect As MSForms.Combobox
Dim comboYearSelect As MSForms.ComboBox
使用
Dim comboMonthSelect, comboDaySelect, comboYearSelect As MSForms.ComboBox
,
只有comboYearSelect
被声明为MSForms.ComboBox
,其他两个被声明为Variant
。
然后编写Option Explicit
并确保在每个Sub / Function中定义每个变量。在你的情况下应该是:
Dim labelGeneral As MSForms.Label
发生错误的Sub listMenu_Change
中的。 MSDN Option Explicit reference
作为一种快速而又肮脏的方式,你可以做这样的事情:
If (listMenu.Selected(0) = True) Then
Controls("labelGeneral").Visible = True
Controls("someOtherName").Visible = True
End If
然而,这会完全打破any MVC pattern并可能导致任何非VBA人感到头晕并发布这样的内容:
如果你想以"正确的方式做到这一点",请从ex-StackOverflow文档中阅读本文,这是非常好的: http://www.riptutorial.com/vba/example/19036/best-practices
答案 1 :(得分:3)
GeneralInformationCreator
本身应该是一个类 - 即使名称也是如此(它的名称就像 的类/类型一样某事,而不是动词就像做某事的过程一样。)
查看您在程序范围内的所有这些声明,在程序范围内实时和死亡 - 它们是局部变量,没有其他人可以看到:
Dim labelGeneral As MSForms.Label
Dim frameGeneral As MSForms.Frame
Dim frameRequestInformation As MSForms.Frame
Dim frameSubmitterInformation As MSForms.Frame
Dim labelAppSelect As MSForms.Label
Dim listAppSelect As MSForms.ListBox
Dim labelDateSelect As MSForms.Label
Dim comboMonthSelect [As Variant], comboDaySelect [As Variant], comboYearSelect As MSForms.ComboBox
Dim labelSubmitterFName [As Variant], labelSubmitterLName As MSForms.Label
Dim inputSubmitterFName [As Variant], inputSubmitterLName As MSForms.TextBox
Dim labelSponsorFName [As Variant], labelSponsorLName As MSForms.Label
Dim inputSponsorFName [As Variant], inputSponsorLName As MSForms.TextBox
Dim labelDepartmentName As MSForms.Label
Dim inputDepartmentName As MSForms.TextBox
通过将它们移动到类模块中的实例级字段(即模块范围变量),您可以公开Public Property Get
访问器,使任何拥有该类实例的人都能够访问这些对象。
所以不要这样:
Private Sub UserForm_Initialize() Call Construct.GeneralInformationCreator Call Construct.ApplicationDetailsCreator With formRequestWizard.listMenu .AddItem ("General Information") .AddItem ("Application Details") '.Selected(0) = True End With End Sub
你将拥有:
Private generalInfoControls As New GeneralInformationCreator
Private appDetailsControls As New ApplicationDetailsCreator
Private Sub UserForm_Initialize()
generalInfoControls.Create Me.Controls
appDetailsControls.Create Me.Controls
With Me.listMenu 'don't refer to the default instance in the form's code-behind... EVER!
.AddItem "General Information"
.AddItem "Application Details"
'.Selected(0) = True
End With
End Sub
Create
是一个采用Controls
参数的过程 - 通过给它Me.Controls
我们传递当前实例的控件集合用户表单,所以方法可以如下所示:
Public Sub Create(ByVal parent As Controls)
Set labelGeneral = parent.Add("Forms.Label.1", "labelGeneral", True)
With labelGeneral
.Font.Size = 12
.Top = 12
.Left = 192
.Height = 14.25
.Width = 42
.Caption = "General Information"
.Name = labelGeneral
End With
'...
请注意,它不再与您的formRequestWizard
表单的默认实例 耦合,并且可以使用任何表单实例' s Controls
收集了它。
我不确定你是否还在按照我的思路进行思考,但这意味着你的处理程序现在可以执行此操作:
Private Sub listMenu_Change()
generalInfoControls.SetVisibility listMenu.Selected(0)
appDetailsControls.SetVisibility listMenu.Selected(1)
End Sub
这意味着您的XxxxCreator
类的SetVisibility
方法看起来像这样:
Public Sub SetVisibility(ByVal isVisible As Boolean)
labelGeneral.Visible = isVisible
frameGeneral.Visible = isVisible
'...