VBA best practices for modules relative to modeless userforms

时间:2016-07-11 20:15:31

标签: excel vba user-input modeless program-flow

I came across this similar issue and read the replies: Modeless form that still pauses code execution

I have been attempting to apply in my own situation the suggestion provided by David Zemens. In my situation, I cannot seem to find an approach that incorporates Mr. Zemen's suggestion without also utilizing a GoTo.

I am wondering if there is a better or more elegant solution.

Here is an outline of what I am doing:

I have a UserForm with a Command Button that begins the code execution that will perform several actions on multiple Excel workbooks. As such, there are a number of blocks of code and the successful completion of one block of code allows for the execution of the subsequent block of code.

At a certain point, depending on the situation, the code might require User input; in other situations, the needed data is obtainable from an Excel. If input is needed from the User, another UserForm is displayed.

The User may need to view several different Excel sheets before entering the input, so the UserForm is modeless. So the code comes to a stop until the User enters the needed input and clicks another Command Button.

It is at this point I am having trouble: how to resume the program flow. Is the only way to 'pick-up where it left-off' is by using a GoTo statement? Or is there some way to organize the modules so there is a single consistent program flow, defined in one spot and not duplicated from the point at which User input might be needed?

2 个答案:

答案 0 :(得分:2)

Here is my take on the problem . Hope I understood the problem correctly.

Assumptions:

  1. There are two user forms.
  2. UserForm1 with a button to start the processing.
  3. UserForm2 with a button to supply intermediate input.
  4. A sub inside a module to start/ launch UserForm1.

VBA Code (for the sub routine)

Sub LaunchUserForm1()
    Dim frm As New UserForm1

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

VBA Code (for 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 Code (for 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

答案 1 :(得分:0)

好的,这是我的想法。

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

我认为可以调整方法I described in the previous answer。但是,除非你付钱让我对所有代码进行反向工程,否则这是不可能的:P

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

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

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

  • 使用这种方法,线程仍然显示vbModal显示frmSelectUpdateSheet,并依靠表单的事件过程来控制进程流/代码执行。

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

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

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

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