Vba 初始化用户表单中的模块变量
我正在尝试使用在UserForm中初始化的变量。但是下面的简单示例只生成一个空MessageBox,而不管我在UserForm中写什么作为输入Vba 初始化用户表单中的模块变量,vba,excel,userform,Vba,Excel,Userform,我正在尝试使用在UserForm中初始化的变量。但是下面的简单示例只生成一个空MessageBox,而不管我在UserForm中写什么作为输入 Public X As String Private Sub Module1() InputForm.Show MsgBox(X) End Sub 输入格式: Private Sub CommandButton_Done_Click() X = InputForm.ListBox1.Value Unload InputForm End
Public X As String
Private Sub Module1()
InputForm.Show
MsgBox(X)
End Sub
输入格式:
Private Sub CommandButton_Done_Click()
X = InputForm.ListBox1.Value
Unload InputForm
End Sub
我是VBA新手,不知道如何调试问题您需要指定
X
位于X
存在的模块上下文中。例如,如果X
作为模块变量存在于模块Module1
中,则可以将CommandButton\u Done\u Click()
子例程更改为
Private子命令按钮\u Done\u Click()
Module1.X=InputForm.ListBox1.Value
卸载输入表单
端接头
重要的是要注意,如果您想让它工作,您不能将保存
X
的模块声明为私有。您的第一个子模块将打开用户表单,因此您的输入框将为空,因此您应该期待一个空msgbox(除非您自动填充该框)
根据我的经验,一个好的实践是在卸载用户表单之前处理变量,因此,您应该在CommandButton\u Done\u Click()中处理它们
1) Sub打开用户表单
2) 分离Sub(初始化)以控制用户窗体打开时发生的情况(控制条目类型、自动填充字段等)
3) 最后一个子项(完成\单击)控制卸载前发生的事情。。。(验证输入为string/int/etc,将输入放入单元格等)
在那条路上有很多问题等着你解决。详细描述所有内容-关键是:翻转依赖项,不要让表单运行
创建一个新的类模块-这将是您的模型:
本课程的成员将了解表单需要了解的一切。这就是你的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
所有表单控件所做的就是操纵模型
属性。因此,如果您希望使用m.Foo=ListBox1.Value
,那么您可以处理ListBox1.Change
,并准确地执行以下操作:
Private Sub ListBox1_Change()
m.Foo = ListBox1.Value
End Sub
现在“确定”按钮需要做的就是关闭表单:
Private Sub CommandButton_Done_Click()
Me.Hide
End Sub
请注意,它是隐藏表单,而不是卸载任何内容。表单是一个对象,这意味着它是由某物在某处创建的,并且某物不会期望它创建的对象自动自毁。因此,您永远不会卸载我
,更不会(如果是这样的话)卸载FormClassName
,因为这将卸载表单的默认实例,并且没有任何地方可以保证表单始终显示在默认实例上:它是一个与其他任何类一样的类,它希望被实例化
为了避免表单自毁,您需要处理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
现在,如果需要,可以在模型
属性设置器中添加逻辑,用调用过程控制的值预先填充表单控件。或者您可以在模型上设置一些IsCancelled
属性,当单击一些CancelButton
时设置这些属性,然后调用代码可以确定表单是否已取消,并有条件地显示MsgBox
需要全局变量:0。如果在标准模块
上声明公共
变量,则该变量应该有效。你到底把第一个代码放在哪里了?反过来看,你将避免许多潜在的问题和处理任何全局变量的需要-看,你不能从userform事件之外编辑userform条目,对吗?我想这就是我想表达的观点。无法从调用条目的子条目修改条目,因此我想不出从那里而不是在以后的子条目上调用它(X)的盗版原因,或者这是逻辑错误吗@MathieuGuindon@urdearboy第一个问题是关闭InputForm
class的默认实例。下一个问题是需要在比实际需要更大的范围内处理变量。在表单的代码中引用表单的默认实例也是一个问题。表单应该能够独立存在,显示表单的代码不需要关心表单上有哪些控件。参见上文我的链接文章;-)@Urderboy正在阅读您的评论…表单控件基本上是公共字段。在使用默认实例时,您实际上是在全局范围内存储状态,并且您完全可以从表单外部调整控件值(见鬼,控件本身!)。诀窍是将范例更改为更面向对象的方式,这样调用代码就不需要知道或关心控件及其值。仅供参考,在该表单的代码中引用表单的默认实例是。我给出了一个快速的答案,希望有帮助:)
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
Me.Hide
End If
End Sub
'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