1

我遇到了这个类似的问题并阅读了回复:仍然暂停代码执行的无模式表单

我一直试图在我自己的情况下应用David Zemens提供的建议。在我的情况下,如果不使用 GoTo,我似乎无法找到一种结合 Zemen 先生的建议的方法。

我想知道是否有更好或更优雅的解决方案。

这是我正在做的事情的概要:

我有一个带有命令按钮的用户窗体,它开始执行代码,它将在多个 Excel 工作簿上执行多个操作。因此,存在许多代码块,并且一个代码块的成功完成允许执行后续代码块。

在某个时候,根据情况,代码可能需要用户输入;在其他情况下,可以从 Excel 中获得所需的数据。如果需要用户输入,则显示另一个用户窗体。

用户在输入之前可能需要查看几个不同的 Excel 工作表,因此用户窗体是无模式的。因此代码停止,直到用户输入所需的输入并单击另一个命令按钮。

正是在这一点上我遇到了麻烦:如何恢复程序流程。“从中断的地方继续”的唯一方法是使用 GoTo 语句吗或者是否有某种方法来组织模块,以便有一个一致的程序流程,在一个地方定义,而不是从可能需要用户输入的地方复制?

4

2 回答 2

2

这是我对这个问题的看法。希望我正确理解了这个问题

假设:

  1. 有两种用户表单。
  2. UserForm1 用一个按钮开始处理。
  3. UserForm2 用一个按钮来提供中间输入。
  4. 模块内用于启动/启动 UserForm1 的子组件。

VBA 代码(用于子程序)

Sub LaunchUserForm1()
    Dim frm As New UserForm1

    '/ Launch the main userform.
    frm.Show vbModeless
End Sub

VBA 代码(用于 UserForm1)

Private Sub cmdStart_Click()
    Dim i       As Long
    Dim linc    As Long
    Dim bCancel As Boolean
    Dim frm     As UserForm2

    '/ Prints 1 to 5 plus the value returned from UserForm2.

    For i = 1 To 5

        If i = 2 Then
            Set frm = New UserForm2
            '/ Launch supplementary form.
            frm.Show vbModeless

'<< This is just a PoC. If you have large number of inputs, better way will be
' to create another prop such as Waiting(Boolean Type) and then manipulate it as and when User
' supplies valid input. Then validate the same in While loop>>

            '/ Wait till we get the value from UserForm2.
            '/ Or the User Cancels the Form with out any input.               
            Do While linc < 1 And (linc < 1 And bCancel = False)
                linc = frm.Prop1
                bCancel = frm.Cancel
                DoEvents
            Loop

            Set frm = Nothing
        End If

        Debug.Print i + linc
    Next

    MsgBox "User Form1's ops finished."

End Sub

VBA 代码(用于 UserForm2)

Dim m_Cancel        As Boolean
Dim m_prop1         As Long

Public Property Let Prop1(lVal As Long)
    m_prop1 = lVal
End Property

Public Property Get Prop1() As Long
   Prop1 = m_prop1
End Property

Public Property Let Cancel(bVal As Boolean)
    m_Cancel = bVal
End Property

Public Property Get Cancel() As Boolean
    Cancel = m_Cancel
End Property

Private Sub cmdlinc_Click()
    '/Set the Property Value to 10
    Me.Prop1 = 10
    Me.Hide
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    '/ Diasble X button

    Me.Cancel = True
    Me.Hide
    Cancel = True

End Sub
于 2016-07-11T21:25:07.327 回答
0

好的,这是我的想法。

frmSelectUpdateSheet当无法以编程方式确定工作表时,您有一个希望使用的用户表单以允许用户选择工作表。问题是,如果您这样做.Show vbModeless(允许用户浏览工作表),那么代码会继续执行,这会导致错误或其他不希望的输出。

我认为可以调整我在上一个答案中描述的方法。但是,除非您付钱让我对您的所有代码进行逆向工程,否则这是不可能的:P

假设您有一个Worksheet需要在此时分配的对象变量(或表示工作表名称的字符串等)(并且该变量Public在范围内),只需使用表单上的 CommandButton 根据所选内容分配它frmSelectUpdateSheet列表框中的项目。

出于多种原因,这可能是一种更好的方法(其中最重要的原因是试图避免针对这种边缘情况重新设计应用程序),例如:

  • 这样可以保留您的表单vbModal,并且确实可以防止用户在此过程中无意中篡改工作表等。

  • 使用这种方法,线程与vbModal显示保持一致frmSelectUpdateSheet,并且您依靠表单的事件过程来控制流程流/代码执行。

  • 它应该更容易(因此也更便宜)实施;无论您是自己做还是外包。

  • 它应该更容易(因此也更便宜)维护。

现在,经过仔细检查,您似乎已经在使用cmdbtnSelect_Click事件处理程序执行这种方法,这使我相信存在相关/后续问题:

工作表名称(在列表框中)不足以让用户识别正确的工作表。因此,如果用户需要能够“滚动”工作表(例如,查看不适合窗口的数据等),则添加一些微调按钮或其他表单控件以允许他们浏览工作表。

于 2016-07-16T03:46:32.877 回答