在UserForm中初始化模块变量

时间:2018-06-14 16:38:10

标签: excel vba excel-vba userform

我尝试使用在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的新手,我不确定如何调试问题

3 个答案:

答案 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