Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vba 初始化用户表单中的模块变量_Vba_Excel_Userform - Fatal编程技术网

Vba 初始化用户表单中的模块变量

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

我正在尝试使用在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 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