8

将 VBA 中的 ProgressBar UserForms 显示为模态还是非模态更好?在 VBA 中开发进度指标的最佳实践是什么?

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

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

资源密集型调用过程也可能导致无模式用户窗体中的事件失败CommandButton_ClickUserForm_Activate

一般来说,使用模式 UserForms 的进度指示器看起来更简单,因为正在执行的代码完全包含在 UserForm 模块中,并且不需要传递变量。

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

因此,虽然可以在无模式用户窗体中拥有一个可重用的进度指示器,但它的可靠性不如从多个模式用户窗体中执行代码。

哪种方式更好?

谢谢!

4

5 回答 5

3

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

于 2010-01-31T00:29:54.153 回答
1

我要结束这个并说莫代尔是赢家。我已经尝试了这两种方法,但你最终试图用无模式的用户表单来填补太多的漏洞。模态更难,因为它更严格,但它鼓励您将代码分解成更小的块,从长远来看,这无论如何都会更好。

于 2010-02-02T16:53:57.197 回答
1

绝对是模态的。如果你打算考虑无模式,你应该在单独的进程外线程上运行它,而不是在 Excel.exe 主线程上。

于 2010-11-29T00:24:28.157 回答
1

我认为最初的主题值得回答,因为这个问题的表述非常好,以至于谷歌首先找到了它。

第 1 节 - 理论

首先要说的是,在模块之间传递变量一点也不难。

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

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

  1. 执行最常规流程的函数不位于UserForm模块中
  2. 您可以从任何地方调用带有进度条的窗口,并且
  3. 例程函数/过程之间的唯一联系是全局变量

在这里多才多艺是一个很大的优势。

第 2 节 - 练习

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

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

Public PCTDone As Single ' 这是已经完成的工作的百分比

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)在任何其他模块中,我们必须具有完成例程的函数或过程/子:

 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
于 2013-08-08T15:31:21.017 回答
0

实际上,您具有以下属性,根据您的需要产生优点/缺点:

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

If you want to block the UI AND let the caller continue, then you need to open the Form in modal mode with Application.OnTime.

于 2018-04-17T15:01:09.040 回答