模块相对于无模式用户表单的VBA最佳实践
我遇到了类似的问题,并阅读答复: 仍然暂停代码执行的无模式
我一直试图在我自己的情况下应用David Zemens提供的build议。 在我的情况下,我似乎找不到一个结合了泽门先生的build议而不使用GoTo的方法。
我想知道是否有更好或更优雅的解决scheme。
以下是我正在做的事情的概要:
我有一个用户窗体与一个命令button开始代码执行将执行多个Excel工作簿上的多个操作。 因此,有多个代码块,并且一个代码块的成功完成允许执行随后的代码块。
在某些情况下,根据情况,代码可能需要用户input; 在其他情况下,所需的数据可以从Excel获得。 如果需要从用户input,则会显示另一个用户窗体。
用户可能需要在inputinput之前查看几个不同的Excel工作表,所以UserForm是无模式的。 因此,代码停止,直到用户input所需的input并单击另一个命令button。
在这一点上,我有麻烦:如何恢复程序stream程。 唯一可以通过GoTo语句来拾取“停止”的方法是? 还是有某种方式来组织模块,所以有一个单一的一致的程序stream,定义在一个点,而不是从用户input可能需要的点重复?
这是我的问题。 希望我正确地理解了这个问题 。
假设:
- 有两个用户表单。
- UserForm1带有一个button来开始处理。
- UserForm2用一个button来提供中间input。
- 一个模块内部的一个子开始/启动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或其他表单控件以允许他们浏览工作表。