我尝试使用在UserForm中初始化的变量。但下面的简单示例只会生成一个空的MessageBox,无论我在UserForm中写什么作为输入。
Public X As String
Private Sub Module1()
InputForm.Show
MsgBox(X)
End Sub
InputForm:
Private Sub CommandButton_Done_Click()
X = InputForm.ListBox1.Value
Unload InputForm
End Sub
我是VBA的新手,我不确定如何调试问题
答案 0 :(得分:3)
您需要指定X
位于X
存在的模块的上下文中。例如,如果X
作为模块Module1
中的模块变量存在,则可以将CommandButton_Done_Click()
子例程更改为
Private Sub CommandButton_Done_Click()
Module1.X = InputForm.ListBox1.Value
Unload InputForm
End Sub
重要的是要注意,如果您希望这样做,则不能将保留X
的模块声明为私有。
答案 1 :(得分:2)
有许多问题等着你在后方沿着那条路咬你。 This article详细描述了所有内容 - 这里是它的关键所在:翻转依赖关系,不要让表单运行该节目。
创建一个新的类模块 - 它将是您的模型:
'class ExampleModel (class module)
Option Explicit
Private Type TModel
Foo As String
'other instance members
End Type
Private this as TModel
Public Property Get Foo() As String
Foo = this.Foo
End Property
Public Property Let Foo(ByVal value As String)
this.Foo = value
End Property
'other properties...
这个班级的成员将是表格需要知道的一切。感谢X
所属的地方。
表单是您的视图 - 它需要了解模型,因此您将其公开给外界:
'class InputForm (UserForm module)
Option Explicit
Private m As ExampleModel ' at module-level, because you'll eventually want it to be WithEvents at one point
Public Property Get Model() As ExampleModel
Set Model = m
End Property
Public Property Set Model(ByVal value As ExampleModel)
Set m = value
End Property
所有表单控件都操作Model
属性。因此,如果您想拥有m.Foo = ListBox1.Value
,那么您可以处理ListBox1.Change
并完全执行此操作:
Private Sub ListBox1_Change()
m.Foo = ListBox1.Value
End Sub
现在所有" OK"按钮需要做的,是关闭形式:
Private Sub CommandButton_Done_Click()
Me.Hide
End Sub
注意它隐藏表单,而不是Unload
任何内容。表单是对象,这意味着它是由某事创建的,某处 - 并且某些东西不会期望它创建的对象自发地自毁。因此,您永远不会Unload Me
,甚至更不会(如果这样做)Unload TheFormClassName
,因为这会卸载表单的默认实例,并且没有任何地方可以保证您的表单总是会显示在默认实例之外:它就像其他任何类一样,它想要实例化。
为了避免自毁表单,您需要处理QueryClose
事件:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
Me.Hide
End If
End Sub
在这里,当用户点击右上角的红色[X]按钮时,我们取消关闭/销毁表单,并隐藏 当前实例 (Me
关键字始终引用类的当前实例。
那么调用代码现在看起来像什么?
'module Module1 (standard module)
Option Explicit
Private Sub Test()
Dim m As ExampleModel
Set m = New ExampleModel
Dim view As InputForm
Set view = New InputForm
Set view.Model = m
view.Show
MsgBox m.Foo
End Sub
现在,如果您愿意,可以在Model
属性设置器中添加逻辑,以使用调用过程控制的值预先填充表单控件。或者,您可以在模型上设置一些IsCancelled
属性,在单击某些CancelButton
时设置该属性,然后调用代码可以确定表单是否已取消,并有条件地显示{{ 1}}。
所需的全局变量:0。
答案 2 :(得分:1)
您的第一个子打开用户窗体,因此您的输入框将为空白,因此您应该期望一个空白的msgbox(除非您自动填充该框)。
一个好的做法(根据我的经验)是在卸载Userform之前使用您的变量,因此,您应该在CommandButton_Done_Click()
1)Sub to Open Userform
2)单独Sub(初始化)以控制用户窗体打开时发生的情况(控制条目类型,自动填充字段等)
3)最终子(Done_Click)来控制卸载之前发生的事情...(验证输入是字符串/ int / etc,在单元格中放置输入等)
Private Sub Module1()
InputForm.Show
End Sub
Private Sub CommandButton_Done_Click()
Msgbox InputForm.ListBox1.Value
Unload InputForm
End Sub