如何让 VBA 代码等到 vbModeless 用户窗体关闭
How to have VBA code wait until vbModeless userform is closed
我想使用无表单用户表单,以便用户在回答用户表单上的问题之前可以导航 excel sheet。我需要暂停或循环代码直到用户窗体关闭(隐藏或卸载)。
与此类似的问题:
但是这里的解决方案不适用于我的应用程序;我的用户窗体是在一个很长的子程序中间打开的,该子程序需要在用户窗体关闭后完成执行。
Dim popupActive as Boolean
popupActive = True
StartingSINT_Popup.Show vbModeless 'Open userform
'have VBA code wait until userform is closed
wait until popupActive = False 'set to false with OK button on userform
'continue code with info input inside StartingSINT_Popup userform
下面的函数不是我写的,但是我已经用了很长时间了,确实有效。
Private Function IsLoaded(ByVal formName As String) As Boolean
Dim frm As Object
For Each frm In VBA.UserForms
If frm.Name = formName Then
IsLoaded = True
Exit Function
End If
Next frm
IsLoaded = False
End Function
您需要对字符串名称进行硬编码,而不是使用表单的 .Name
属性,因为表单可能尚未加载且不包含此 属性。
以下是如何使用此功能的一小段:
Do While IsLoaded("StartingSINT_Popup")
Debug.Print Time; " StartingSINT_Popup Is Loaded!"
Loop
My userform is opened in the middle of a long subroutine which needs to finish executing after the userform is closed.
您的程序做的事情太多,需要分解成更小、更专业的程序。
正确的做法是将范例从过程转变为事件驱动.
而不是像这样显示表单的默认实例:
StartingSINT_Popup.Show vbModeless 'Open userform
有一个 class 模块包含它的 WithEvent
个实例:
Private WithEvents popup As StartingSINT_Popup
Private Sub Class_Initialize()
Set popup = New StartingSINT_Popup
End Sub
Public Sub Show()
popup.Show vbModeless
End Sub
Private Sub popup_Closed()
' code to run when the form is closed
End Sub
在表单的代码隐藏中,声明一个 Closed
事件:
Public Event Closed()
然后在 QueryClose
处理程序中提出它:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then 'controlbox was clicked (the "red X button")
Cancel = True 'would otherwise destroy the form instance
Me.Hide 'always hide, never unload
End If
RaiseEvent Closed
End Sub
现在假设您将那个命名为 class PopupPresenter
,您的程序现在可以这样做:
Private presenter As PopupPresenter
Public Sub DoStuff()
Set presenter = New PopupPresenter
'do stuff...
presenter.Show
'rest of the code in this scope will run immediately AND THIS IS FINE
End Sub
将演示者保持在模块级别,以便对象在 DoStuff
完成时不会超出范围,并传递任何 variables/values 或声明演示者对象需要在以下时间完成其工作表格已关闭。您可以通过公开属性或 public fields/variables(虽然更喜欢属性,但这是另一个主题)来做到这一点:
Private WithEvents popup As StartingSINT_Popup
Public Foo As String
Private Sub Class_Initialize()
Set popup = New StartingSINT_Popup
End Sub
Public Sub Show()
popup.Show vbModeless
End Sub
Private Sub popup_Closed()
' code to run when the form is closed
MsgBox Foo
End Sub
Private presenter As PopupPresenter
Public Sub DoStuff()
Set presenter = New PopupPresenter
'do stuff...
presenter.Show
presenter.Foo = "some data"
'rest of the code in this scope will run immediately AND THIS IS FINE
End Sub
这是一个替代方案...
1.在原来的[public]模块(调用userform 1的那个)中,声明一个public布尔变量。
Public done As Boolean
2。在用户表单 1 中,
一个。为布尔变量分配默认值
b。调用用户窗体 2
c。做一个 while 循环...
- 检查默认值
- 包括 DoEvents 方法(允许用户窗体 2 在循环中继续推进)
代码
Private Sub event_click()
done = False
Dim userform2 As New userform
userform2.Show Modeless
'This will loop through until userform2 changes done variable to "True"
Do While done = False
DoEvents
Loop
'Code after done with userform2
dataSource.Refresh
End Sub
3。在用户窗体 2 中,更改布尔值以中断循环
代码
Private Sub submit_Click()
'Userform submit code
Dim name As String
name = TextBox.Value
sql = "INSERT INTO table (field) VALUES ('" & name & "')"
Call query(sql)
'IMPORTANT: change Boolean variable to break loop before exiting userform
done = True
Unload Me
End Sub
我想使用无表单用户表单,以便用户在回答用户表单上的问题之前可以导航 excel sheet。我需要暂停或循环代码直到用户窗体关闭(隐藏或卸载)。
与此类似的问题:
Dim popupActive as Boolean
popupActive = True
StartingSINT_Popup.Show vbModeless 'Open userform
'have VBA code wait until userform is closed
wait until popupActive = False 'set to false with OK button on userform
'continue code with info input inside StartingSINT_Popup userform
下面的函数不是我写的,但是我已经用了很长时间了,确实有效。
Private Function IsLoaded(ByVal formName As String) As Boolean
Dim frm As Object
For Each frm In VBA.UserForms
If frm.Name = formName Then
IsLoaded = True
Exit Function
End If
Next frm
IsLoaded = False
End Function
您需要对字符串名称进行硬编码,而不是使用表单的 .Name
属性,因为表单可能尚未加载且不包含此 属性。
以下是如何使用此功能的一小段:
Do While IsLoaded("StartingSINT_Popup")
Debug.Print Time; " StartingSINT_Popup Is Loaded!"
Loop
My userform is opened in the middle of a long subroutine which needs to finish executing after the userform is closed.
您的程序做的事情太多,需要分解成更小、更专业的程序。
正确的做法是将范例从过程转变为事件驱动.
而不是像这样显示表单的默认实例:
StartingSINT_Popup.Show vbModeless 'Open userform
有一个 class 模块包含它的 WithEvent
个实例:
Private WithEvents popup As StartingSINT_Popup
Private Sub Class_Initialize()
Set popup = New StartingSINT_Popup
End Sub
Public Sub Show()
popup.Show vbModeless
End Sub
Private Sub popup_Closed()
' code to run when the form is closed
End Sub
在表单的代码隐藏中,声明一个 Closed
事件:
Public Event Closed()
然后在 QueryClose
处理程序中提出它:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then 'controlbox was clicked (the "red X button")
Cancel = True 'would otherwise destroy the form instance
Me.Hide 'always hide, never unload
End If
RaiseEvent Closed
End Sub
现在假设您将那个命名为 class PopupPresenter
,您的程序现在可以这样做:
Private presenter As PopupPresenter
Public Sub DoStuff()
Set presenter = New PopupPresenter
'do stuff...
presenter.Show
'rest of the code in this scope will run immediately AND THIS IS FINE
End Sub
将演示者保持在模块级别,以便对象在 DoStuff
完成时不会超出范围,并传递任何 variables/values 或声明演示者对象需要在以下时间完成其工作表格已关闭。您可以通过公开属性或 public fields/variables(虽然更喜欢属性,但这是另一个主题)来做到这一点:
Private WithEvents popup As StartingSINT_Popup
Public Foo As String
Private Sub Class_Initialize()
Set popup = New StartingSINT_Popup
End Sub
Public Sub Show()
popup.Show vbModeless
End Sub
Private Sub popup_Closed()
' code to run when the form is closed
MsgBox Foo
End Sub
Private presenter As PopupPresenter
Public Sub DoStuff()
Set presenter = New PopupPresenter
'do stuff...
presenter.Show
presenter.Foo = "some data"
'rest of the code in this scope will run immediately AND THIS IS FINE
End Sub
这是一个替代方案...
1.在原来的[public]模块(调用userform 1的那个)中,声明一个public布尔变量。
Public done As Boolean
2。在用户表单 1 中,
一个。为布尔变量分配默认值
b。调用用户窗体 2
c。做一个 while 循环...
- 检查默认值
- 包括 DoEvents 方法(允许用户窗体 2 在循环中继续推进)
代码
Private Sub event_click()
done = False
Dim userform2 As New userform
userform2.Show Modeless
'This will loop through until userform2 changes done variable to "True"
Do While done = False
DoEvents
Loop
'Code after done with userform2
dataSource.Refresh
End Sub
3。在用户窗体 2 中,更改布尔值以中断循环
代码
Private Sub submit_Click()
'Userform submit code
Dim name As String
name = TextBox.Value
sql = "INSERT INTO table (field) VALUES ('" & name & "')"
Call query(sql)
'IMPORTANT: change Boolean variable to break loop before exiting userform
done = True
Unload Me
End Sub