Это лучше показать прогрессбар пользовательских форм в VBA как модальный или немодальный?
лучше показать прогрессбар пользовательских форм в VBA как модальный или немодальный? Каковы наилучшие методы разработки показателей прогресса в VBA?
Modeless UserForms требуют использования Application.Interactive = False
, тогда как модальные UserForms по самой своей природе блокируют любое взаимодействие с приложением, пока основная процедура не завершится или не будет отменена.
если Application.Interactive = False
используется, однако, клавиша Esc прерывает выполнение кода, поэтому использование Application.EnableCancelKey = xlErrorHandler
и обработка ошибок (Err.Number = 18
) требуется как в пользовательской форме, так и в вызывающей процедуре.
ресурсоемкие процедуры вызова также могут привести к CommandButton_Click
и UserForm_Activate
события осечки в modeless UserForms.
в общем, индикаторы прогресса, использующие модальные пользовательские формы, кажутся проще, потому что выполняемый код полностью содержится в модуле UserForm, и меньше необходимости в передаче переменных.
проблема, однако, с использованием модальных пользовательских форм для индикаторы прогресса - это отдельный модуль UserForm, необходимый для каждой процедуры, которая нуждается в индикаторе прогресса, поскольку вызывающая процедура должна быть внутри процедуры UserForm_Activate.
таким образом, хотя можно иметь один многоразовый индикатор прогресса в modeless UserForm, он будет менее надежным, чем выполнение кода из нескольких модальных UserForms.
какой путь лучше?
спасибо!
5 ответов
есть также третий способ, используя Application.StatusBar
.
Вы даже можете имитировать истинный индикатор выполнения, используя последовательность символов U+25A0 и U+25A1.
Я собираюсь закрыть это и сказать, что Modal является победителем. Я пробовал в обоих направлениях, но вы в конечном итоге пытаетесь закрыть слишком много лазеек с помощью modeless userforms. Modal сложнее, потому что он более строгий, но он побуждает вас разбивать свой код на более мелкие куски, что в конечном итоге лучше.
Определенно Модала. Если вы собираетесь считать Modeless, вы должны запустить его в отдельном потоке вне процесса, а не в Excel.основной поток ехе.
Я думаю, что первоначальная тема стоит ответа, так как вопрос был сформулирован так красиво, что google находит его первым.
Раздел 1-Теория
первым делом сказать, что передать переменные между модулями совсем не сложно.
единственное, что вам нужно сделать, это создать отдельный модуль и поставить там все глобальные переменные. Тогда вы сможете читать их везде и во всем формы, листы, модули.
вторая вещь окно должно быть НЕМОДАЛЬНОЙ. Почему это? Ответ чтобы сохранить мобильность кода, то есть
- функция, в которой выполняется самый рутинный процесс, не должна находиться в модуле UserForm
- вы можете вызвать окно с индикатором прогресса отовсюду и
- единственное соединение между обычной функцией / процедурой являются ли глобальные переменные
Это большое преимущество, чтобы быть универсальным здесь.
Раздел 2-Практика
1) создать модуль "декларации" с глобальными переменными:
Public StopForce Как Целое Число 'эта переменная будет использоваться как индикатор того, что пользователь нажал кнопку Cancel
Общественный PCTDone Как Одиночный "это % от уже проделанной работы
Public CurrentFile Как Строка 'любой другой параметр, который мы хотим перенести в форму.
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
на самом деле у вас есть следующие свойства, в результате чего плюсы/минусы в зависимости от ваших потребностей:
Type | Impact on UI | Impact on caller execution
----------|--------------|-----------------------------
Modal | Blocked | Blocked until Form is closed
Modeless | Not blocked | Continues
Если вы хотите заблокировать пользовательский интерфейс и позволить вызывающему абоненту продолжить, то вам нужно открыть форму в модальном режиме с Application.OnTime
.