在 VBA 中将 ProgressBar UserForms 显示为模态还是非模态更好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2169975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it better to show ProgressBar UserForms in VBA as modal or modeless?
提问by Kuyenda
Is it better to show ProgressBar UserForms in VBA as modal or modeless? What are the best practices for developing progress indicators in VBA?
在 VBA 中将 ProgressBar UserForms 显示为模态还是非模态更好?在 VBA 中开发进度指标的最佳实践是什么?
Modeless UserForms require the use of Application.Interactive = False
, whereas Modal UserForms by their very nature block any interaction with the application until the core procedure has finished, or is cancelled.
无模式用户窗体需要使用Application.Interactive = False
,而模式用户窗体本质上会阻止与应用程序的任何交互,直到核心过程完成或被取消。
If Application.Interactive = False
is used, however, the Esc key interrupts code execution, so the use of Application.EnableCancelKey = xlErrorHandler
and error handling (Err.Number = 18
) is required in both the UserForm and the calling procedure.
Application.Interactive = False
但是,如果使用 Esc 键会中断代码执行,因此在用户窗体和调用过程中都需要使用Application.EnableCancelKey = xlErrorHandler
错误处理 ( Err.Number = 18
)。
Resource intensive calling procedures can also result in CommandButton_Click
and UserForm_Activate
events misfiring in modeless UserForms.
资源密集型调用程序也能导致CommandButton_Click
和UserForm_Activate
事件在无模式用户窗体哑火。
In general, progress indicators that use modal UserForms seem simpler, because the code that is being executed is fully contained in the UserForm module, and there is less need for passing of variables.
一般来说,使用模态 UserForms 的进度指示器看起来更简单,因为正在执行的代码完全包含在 UserForm 模块中,并且不需要传递变量。
The problem, however, with using modal UserForms for progress indicators is that a separate UserForm module is required for every procedure that needs a progress indicator, because the calling procedure has to be inside the UserForm_Activate procedure.
然而,使用模式用户窗体作为进度指示器的问题在于,每个需要进度指示器的过程都需要一个单独的用户窗体模块,因为调用过程必须在 UserForm_Activate 过程中。
So, while it is possible to have a single reusable progress indicator in a modeless UserForm, it will be less reliable than executing the code from within multiple modal UserForms.
因此,虽然在无模式用户窗体中可以有一个可重用的进度指示器,但它不如从多个模式用户窗体中执行代码可靠。
Which way is better?
哪种方式更好?
Thanks!
谢谢!
采纳答案by Kuyenda
I am going to close this one out and say Modal is the winner. I have tried both ways, but you end up trying to close too many loopholes with modeless userforms. Modal is more difficult because it is more strict, but it encourages you to break up your code into smaller chunks which is better in the long run anyway.
我要结束这个,并说莫代尔是赢家。我已经尝试了两种方法,但是您最终试图用无模式的用户表单来关闭太多漏洞。Modal 更难,因为它更严格,但它鼓励您将代码分解成更小的块,从长远来看这更好。
回答by GSerg
There's also a third way, using the Application.StatusBar
.
You can even simulate a true progress bar by using a sequence of U+25A0 and U+25A1 characters.
还有第三种方法,使用Application.StatusBar
. 您甚至可以使用 U+25A0 和 U+25A1 字符序列来模拟真正的进度条。
回答by Anonymous Type
Definately Modal. If you are going to consider Modeless, you ought to run it on a seperate out-of-process thread and not on the Excel.exe main thread.
绝对是模态。如果您打算考虑无模式,则应该在单独的进程外线程上运行它,而不是在 Excel.exe 主线程上运行。
回答by user2664434
I think that the initial topic is worth of replying since the question was formulated so nicely that google finds it first.
我认为最初的主题值得回答,因为问题的表述非常好,谷歌首先找到了它。
Section 1 - Theory
第 1 节 - 理论
The first thingto say is that to transfer the variables between the modules is not difficult at all.
首先要说的是,在模块之间传递变量一点也不困难。
The only thing you need to do is to create a separate module and put there all the global variables. Then you will be able to read them everywhere in all forms, sheets, modules.
您唯一需要做的就是创建一个单独的模块并将所有全局变量放在那里。然后,您将能够以各种形式、工作表、模块随处阅读它们。
The second thingis the window should be a MODELESS. Why that? The answer is to keep the mobility of the code, i.e.
第二件事是窗口应该是MODELESS。为什么?答案是保持代码的移动性,即
- the function where the most routine process is executed is not to be located in the UserForm module
- you can call the window with progress bar from everywhere and
- the only connection between the routine function/procedure are the global variables
- 执行最常规流程的函数不要位于UserForm模块中
- 您可以从任何地方调用带有进度条的窗口
- 例程函数/过程之间的唯一连接是全局变量
This is a great advantage to be versatile here.
这是在这里多才多艺的一大优势。
Section 2 - Practice
第 2 节 - 练习
1) Create a module "Declaration"with the global variables:
1)使用全局变量创建一个模块“声明”:
Public StopForce As Integer 'this variable will be used as an indicator that the user pressed the cancel button
Public StopForce As Integer '此变量将用作用户按下取消按钮的指示器
Public PCTDone As Single ' this is the % of the work that was done already
Public PCTDone As Single ' 这是已完成工作的百分比
Public CurrentFile As String ' any other parameter that we want to transfer to the form.
Public CurrentFile As String ' 我们要传输到表单的任何其他参数。
2) Create the form with the button. In OnClick event of the button there should be a code where we refer to the global variable StopForcein Declarationmodule
2) 用按钮创建表单。在按钮的 OnClick 事件中应该有一个代码,我们在声明模块中引用全局变量StopForce
Private Sub CommandButton1_Click()
Declaration.StopForce = 1
End Sub
3) Add one procedure where you update the progress bar
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) in any other module we must have the functions or the procedure/sub where the routine is done:
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
回答by jeromerg
Actually you have following properties, resulting in pros/cons depending on your need:
实际上你有以下属性,根据你的需要产生优点/缺点:
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
.
如果您想阻止 UI 并让调用者继续,那么您需要使用Application.OnTime
.