如何让VBA代码等到关闭vbModeless用户窗体

时间:2019-04-30 18:00:36

标签: excel vba userform

我想使用无格式的用户表单,以便用户在回答用户表单上的问题之前可以浏览excel工作表。我需要暂停或循环执行代码,直到关闭用户窗体(隐藏或卸载)。

与此类似的问题: How can I wait for a specific code to run while when form is closed and is set to vbModeless? 但是这里的解决方案不适用于我的应用程序;我的用户窗体是在一个长子程序的中间打开的,该子程序需要在用户窗体关闭后完成执行。

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

3 个答案:

答案 0 :(得分:4)

  

我的用户窗体在一个长子例程的中间打开,该例程需要在用户窗体关闭后完成执行。

您的过程执行了太多操作,需要分解为更小,更专业的过程。

正确的方法是将范例从过程转换为事件驱动

与其像这样显示表单的默认实例:

StartingSINT_Popup.Show vbModeless 'Open userform

具有一个包含其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

现在说您将类命名为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完成时对象不会超出范围,并在关闭表单时传递任何变量/值或声明演示者对象需要完成其工作的状态。您可以通过公开属性或公共字段/变量来做到这一点(尽管首选属性,但这是另一个主题):

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 :(得分:2)

我没有编写以下函数,但是已经使用了很长时间了,并且可以正常工作。

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

答案 2 :(得分:0)

这是另一种选择...

1。在原始的[public]模块(调用用户表单1的模块)中,声明一个公共布尔变量。

Public done As Boolean

2。在用户表格1中,

a。为布尔变量分配默认值

b。致电用户表格2

c。做一个do 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