将VBA中的ProgressBar UserForms显示为模态还是无模式更好?

时间:2010-01-30 23:47:04

标签: vba modal-dialog userform modeless progress-indicator

将VBA中的ProgressBar UserForms显示为模态还是无模式更好?在VBA中制定进度指标的最佳做法是什么?

无模式UserForms需要使用Application.Interactive = False,而Modal UserForms本质上阻止与应用程序的任何交互,直到核心过程完成或被取消。

但是,如果使用Application.Interactive = False,则Esc键会中断代码执行,因此在UserForm和调用过程中都需要使用Application.EnableCancelKey = xlErrorHandler和错误处理(Err.Number = 18

资源密集型调用过程也可能导致CommandButton_ClickUserForm_Activate事件在无模式UserForms中失效。

通常,使用模态UserForms的进度指示器似乎更简单,因为正在执行的代码完全包含在UserForm模块中,并且不需要传递变量。

然而,使用模式UserForms作为进度指示器的问题是每个需要进度指示器的过程都需要一个单独的UserForm模块,因为调用过程必须在UserForm_Activate过程中。

因此,虽然在无模式UserForm中可以有一个可重用的进度指示器,但它比在多个模态用户表单中执行代码的可靠性低。

哪种方式更好?

谢谢!

5 个答案:

答案 0 :(得分:3)

还有第三种方法,使用Application.StatusBar。 您甚至可以使用一系列U + 25A0和U + 25A1字符来模拟真正的进度条。

答案 1 :(得分:1)

我将关闭这一个并说Modal是胜利者。我已经尝试了两种方法,但你最终试图通过无模式用户表单来关闭太多漏洞。 Modal更难,因为它更严格,但它鼓励你将你的代码分解成更小的块,从长远来看这是更好的。

答案 2 :(得分:1)

绝对莫代尔。 如果你要考虑使用Modeless,你应该在一个单独的进程外线程上运行它,而不是在Excel.exe主线程上。

答案 3 :(得分:1)

我认为最初的主题值得回复,因为问题的制定非常好,谷歌首先发现它。

第1节 - 理论

要说的第一件事 就是要在模块之间传输变量并不困难。

您唯一需要做的就是创建一个单独的模块并将所有全局变量放在那里。然后,您将能够以各种形式,表格,模块随处阅读它们。

第二件事 是窗口应该是MODELESS。为什么? 答案是以保持代码的移动性,即

  1. 执行最常规进程的功能不在UserForm模块中
  2. 您可以从任何地方使用进度条调用窗口
  3. 例程函数/过程之间唯一的连接是全局变量
  4. 这是多功能的一个很大的优势。

    第2节 - 练习

    1)使用全局变量创建模块“声明”

    Public StopForce As Integer '此变量将用作用户按下取消按钮

    的指示符

    公共PCTDone为单一 '这是已经完成的工作的百分比

    Public CurrentFile As String '我们要转移到表单的任何其他参数。

    2)使用按钮创建表单。在按钮的OnClick事件中,应该有一个代码,我们在声明模块中引用全局变量 StopForce

     Private Sub CommandButton1_Click()
    
     Declaration.StopForce = 1
      End Sub
    

    3)添加一个更新进度条的程序

    Sub UpdateProgressBar(PCTDone_in As Single)
    With UserForm1
        ' Update the Caption property of the Frame control.
        .FrameProgress.Caption = Format(PCTDone_in, "0%")
        ' Widen the Label control.
        .LabelProgress.Width = PCTDone_in * _
            (.FrameProgress.Width)
        ' Display the current file from global variable   
        .Label1.Caption = Declaration.CurrentFile
    End With
    End Sub
    

    4)在任何其他模块中,我们必须具有完成例程的函数或过程/ sub:

     For i=1 to All_Files
    
     Declaration.CurrentFile = myFiles (i)
    
     FormFnc.UpdateProgressBar (i / .Range("C11").Value)
    
    
     DoEvents
    
     If Declaration.StopForce = 1 Then
        GoTo 3
     End If
    
     Next i
    

答案 4 :(得分:0)

实际上,您有以下属性,根据您的需要产生利弊:

Type      | Impact on UI | Impact on caller execution
----------|--------------|-----------------------------
Modal     | Blocked      | Blocked until Form is closed
Modeless  | Not blocked  | Continues

如果要阻止用户界面并让呼叫者继续,则需要使用Application.OnTime以模态模式打开表单。