Это лучше показать прогрессбар пользовательских форм в 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-Теория

первым делом сказать, что передать переменные между модулями совсем не сложно.

единственное, что вам нужно сделать, это создать отдельный модуль и поставить там все глобальные переменные. Тогда вы сможете читать их везде и во всем формы, листы, модули.

вторая вещь окно должно быть НЕМОДАЛЬНОЙ. Почему это? Ответ чтобы сохранить мобильность кода, то есть

  1. функция, в которой выполняется самый рутинный процесс, не должна находиться в модуле UserForm
  2. вы можете вызвать окно с индикатором прогресса отовсюду и
  3. единственное соединение между обычной функцией / процедурой являются ли глобальные переменные

Это большое преимущество, чтобы быть универсальным здесь.

Раздел 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.