Что лучше: отображать пользовательские формы ProgressBar в VBA как модальные или немодальные?

Что лучше: отображать пользовательские формы ProgressBar в VBA как модальные или немодальные? Каковы лучшие практики для разработки индикаторов прогресса в VBA?

Немодальные пользовательские формы требуют использования Application.Interactive = False, тогда как модальные пользовательские формы по самой своей природе блокируют любое взаимодействие с приложением до тех пор, пока основная процедура не завершится или не будет отменена.

Однако, если используется Application.Interactive = False, клавиша Esc прерывает выполнение кода, поэтому использование Application.EnableCancelKey = xlErrorHandler и обработка ошибок (Err.Number = 18) требуется как в пользовательской форме, так и в вызывающей процедуре.

Процедуры вызова, интенсивно использующие ресурсы, также могут приводить к пропускам событий CommandButton_Click и UserForm_Activate в немодальных пользовательских формах.

В целом индикаторы выполнения, использующие модальные пользовательские формы, кажутся более простыми, поскольку выполняемый код полностью содержится в модуле UserForm, и необходимость в передаче переменных меньше.

Однако проблема с использованием модальных пользовательских форм для индикаторов выполнения заключается в том, что для каждой процедуры, которой требуется индикатор выполнения, требуется отдельный модуль UserForm, поскольку вызывающая процедура должна находиться внутри процедуры UserForm_Activate.

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

Какой способ лучше?

Спасибо!


person Kuyenda    schedule 30.01.2010    source источник


Ответы (5)


Есть также третий способ - использовать Application.StatusBar. Вы даже можете смоделировать настоящий индикатор выполнения, используя последовательность символов U + 25A0 и U + 25A1.

person GSerg    schedule 31.01.2010
comment
Спасибо за предложение GSerg, но я пробовал использовать это в прошлом, но Excel 2007 перестает обновлять окно и показывает «Не отвечает» в верхней части окна приложения. - person Kuyenda; 31.01.2010
comment
Я не слишком разбираюсь в Office 2007, но что, если вы вызовете DoEvents сразу после установки значения StatusBar? - person GSerg; 31.01.2010
comment
Ха, это сработало. Вау, это хороший вариант, не так ли! Спасибо, GSerg! - person Kuyenda; 31.01.2010
comment
Одна из проблем с использованием StatusBar для индикаторов прогресса заключается в том, что нет возможности предоставить кнопку отмены. - person Kuyenda; 01.02.2010
comment
хороший метод, но на самом деле он не отвечает на вопрос о передовой практике в модальном / немодальном режиме, с техническим ответом на использование строки состояния. - person Anonymous Type; 29.11.2010
comment
Проблема с DoEvents заключается в том, что пользователь может выполнять итерацию с электронной таблицей во время выполнения макроса, и это может привести к проблемам ... не круто! - person Raf; 29.11.2016

Я собираюсь закрыть это и сказать, что Modal - победитель. Я пробовал оба способа, но в итоге вы пытаетесь закрыть слишком много лазеек с помощью немодальных пользовательских форм. Модальный режим сложнее, потому что он более строг, но он побуждает вас разбивать код на более мелкие части, что в любом случае лучше в долгосрочной перспективе.

person Kuyenda    schedule 02.02.2010

Определенно модально. Если вы собираетесь рассматривать режим без режима, вам следует запускать его в отдельном внепроцессном потоке, а не в основном потоке Excel.exe.

person Anonymous Type    schedule 29.11.2010

Я думаю, что на начальную тему стоит ответить, поскольку вопрос сформулирован так красиво, что Google находит его первым.

Раздел 1 - Теория

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

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

Второе - окно должно быть БЕСМОДЕЛЬНЫМ. Почему так? Ответ: сохранить подвижность кода, т. Е.

  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
person user2664434    schedule 08.08.2013
comment
Обратите внимание, что немодальные пользовательские формы вообще не работают в Mac OS. - person Wolfgang Fahl; 30.05.2017

На самом деле у вас есть следующие свойства, что дает плюсы / минусы в зависимости от ваших потребностей:

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

Если вы хотите заблокировать пользовательский интерфейс и позволить вызывающему абоненту продолжить, вам нужно открыть форму в модальном режиме с помощью Application.OnTime.

person jeromerg    schedule 17.04.2018
comment
Я получаю сообщение об ошибке при попытке открыть форму через Application.OnTime (пробовал разные варианты). Какой синтаксис вы используете для этого? - person Albin; 07.12.2019