Лучше ли показывать пользовательские формы ProgressBar в VBA как модальные или немодальные? - PullRequest
8 голосов
/ 31 января 2010

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

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

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

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

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

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

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

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

Спасибо!

Ответы [ 5 ]

3 голосов
/ 31 января 2010

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

1 голос
/ 08 августа 2013

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

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

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

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

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

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

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

Раздел 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
1 голос
/ 29 ноября 2010

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

1 голос
/ 02 февраля 2010

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

0 голосов
/ 17 апреля 2018

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

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

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

...