模块相对于无模式用户表单的VBA最佳实践

我遇到了类似的问题,并阅读答复: 仍然暂停代码执行的无模式

我一直试图在我自己的情况下应用David Zemens提供的build议。 在我的情况下,我似乎找不到一个结合了泽门先生的build议而不使用GoTo的方法。

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

以下是我正在做的事情的概要:

我有一个用户窗体与一个命令button开始代码执行将执行多个Excel工作簿上的多个操作。 因此,有多个代码块,并且一个代码块的成功完成允许执行随后的代码块。

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

用户可能需要在inputinput之前查看几个不同的Excel工作表,所以UserForm是无模式的。 因此,代码停止,直到用户input所需的input并单击另一个命令button。

在这一点上,我有麻烦:如何恢复程序stream程。 唯一可以通过GoTo语句来拾取“停止”的方法是? 还是有某种方式来组织模块,所以有一个单一的一致的程序stream,定义在一个点,而不是从用户input可能需要的点重复?

这是我的问题。 希望我正确地理解了这个问题

假设:

  1. 有两个用户表单。
  2. UserForm1带有一个button来开始处理。
  3. UserForm2用一个button来提供中间input。
  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 

好的,这是我的想法。

您有一个用户frmSelectUpdateSheet ,您希望使用它来允许用户select工作表时,无法以编程方式确定工作表。 问题是,如果你做.Show vbModeless (允许用户导航工作表),那么代码继续执行,否则会导致错误或不希望的输出。

我认为可以调整我在前面的答案中描述的方法。 然而,除非你付我来逆向工程你所有的代码,否则这是不可能的

假设你有一个Worksheet对象variables(或一个表示工作表名称的string等)需要在这一点上分配(并且这个variables是作用域中的Public ),只需使用表单上的CommandButton来根据frmSelectUpdateSheet列表框中的所选项目。

这可能是一个优越的方法,其原因很多(其中最重要的一点就是为了避免应用程序重新devise这类边缘情况),比如:

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

  • 使用这种方法,线程将保持在vbModal显示的frmSelectUpdateSheet ,并依靠窗体的事件过程来控制stream程/代码的执行。

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

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

现在,仔细观察,看起来你已经在使用cmdbtnSelect_Click事件处理程序进行这种处理, 这导致我相信有一个相关/后续问题:

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