Визуализация работы макроса при помощи прогресс-бара

Прогресс-бар на VBA

Данный прогресс-бар позволяет отображать ход выполнения любого макроса.

Для использования этого индикатора перетащите из файла-примера в свой файл модуль класса ProgressIndicator и форму F_Progress

Использовать прогресс бар сравнительно просто - достаточно добавить в макрос несколько строк кода:

Sub ПростейшийПримерИспользованияПрогрессБара()
    Dim pi As New ProgressIndicator    ' создаём новый прогресс-бар
    pi.Show "Подождите, работает макрос"    ' отбражаем индикатор

    ' здесь код вашего макроса

    pi.Hide    ' закрываем индикатор
End Sub

Sub ПримерИспользованияПрогрессБара()
 
    КоличествоЗапусковВнешнегоМакроса = 3000
 
    Dim pi As New ProgressIndicator    ' создаём новый прогресс-бар
    pi.Show "Форматирование ячеек"    ' отбражаем индикатор

    ' первое действие (на шкале индикатора от 0 до 95 процентов) - это окраска ячеек
    pi.StartNewAction 0, 95, "Окраска ячеек", , , КоличествоЗапусковВнешнегоМакроса
 
 
 
    ' цикл с вызовом внешнего макроса "ФорматированиеЯчейки"
    For i = 1 To КоличествоЗапусковВнешнегоМакроса
 
        ' инициируем очередное действие в индикаторе
        pi.SubAction , "Обрабатывается ячейка $index из $count", "$time"
 
        ' собственно, код цикла
        ФорматированиеЯчейки i
    Next
 
    ' всё покрасили - теперь пора чистить ячейки )
    pi.StartNewAction 95, 100, "Очистка ячеек"
    Cells.Clear
 
    pi.Hide    ' закрываем индикатор
End Sub
 
Sub ФорматированиеЯчейки(ByVal n As Long)    ' вызываемый макрос
    Cells(n).Interior.ColorIndex = 15: Cells(n).BorderAround xlContinuous
End Sub

 

Давайте рассмотрим подробнее работу с индикатором.

 

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

Dim pi As New ProgressIndicator    ' создаём новый прогресс-бар

 

Итак, прогресс-бар создан, и теперь надо его отобразить.

Для этого мы используем метод Show объекта типа ProgressIndicator:

pi.Show "Форматирование ячеек"    ' отбражаем индикатор

При использовании метода Show мы сразу задаём заголовок индикатора (можно здесь указать название вашего макроса)

Индикатор появился на экране - но полоса не отображается, ибо процент выполнения по-умолчанию равен нулю.

 

Для каждого действия мы будем задавать начальный и конечный процент выполнения задачи

К примеру, если первое действие вашего макроса занимает по времени примерно пятую часть от времени выполнения всего макроса,
то мы укажем интервал для индикатора от 0% до 20%:

pi.StartNewAction 0, 20

Как вы заметили, для запуска очередного действия используется метод StartNewAction объекта ProgressIndicator.

При вызове этого метода можно сразу задать текст для каждой из 3 текстовых строк индикатора:

pi.StartNewAction 0, 20, "Текст первой строки", "Текст строки 2", "Текст строки 3"

Если действие состоит из нескольких отдельных "поддействий", то можно также сразу задать и количество этих "поддействий"

(например, основное действие - это форматирование ячеек (от 0% до 20% индикатора), а поддействия - это окраска отдельных ячеек (первая строка - от 0% до 1% индикатора, вторая строка - от 1% до 2%, и т.д.))

Чтобы нам не мучиться с расчётами этих процентов, мы просто задаём количество действий (например, количество форматируемых ячеек, равное 3000),
и индикатор сам разделит диапазон от 0% до 20% на 3000 равных частей, плавно увеличивая длину полосы индикатора по мере форматирования отдельных ячеек.

 pi.StartNewAction 0, 20, "Окраска ячеек", , , 3000

 

Чтобы уведомить индикатор об очередном "поддействии" внутри цикла, мы используем метод SubAction объекта ProgressIndicator

' инициируем очередное действие в индикаторе
        pi.SubAction , "Обрабатывается ячейка $index из $count", "$time"

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

В этом случае (если значения некоторых из 3 строк индикатора не заданы), эти строки не изменяются
(в первой строке индикатора останется текст, заданный ранее при использовании метода StartNewAction)

 

Кроме того, в тексте для строк индикатора можно использовать следующие ключевые слова:

  • $index и $count - для вывода строк типа "Обрабатывается ячейка 515 из 3000",
  • $time - для вывода ожидаемого времени до окончания макроса

(макрос анализирует текущий процент выполнения и затраченное время, и предсказывает, сколько времени осталось до окончания всех действий)

Если же необходимо просто увеличить длину полоски индикатора - можете использовать метод SubAction без параметров:

pi.SubAction

 

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

Вполне допустим следующий код:

    pi.StartNewAction 5, 20, "Действие 1"    ' начинаем не с нуля
    pi.StartNewAction 20, 50, "Действие 2"    ' начинается сразу после предыдущего
    pi.StartNewAction 35, 60, "Действие 3"    ' начинается раньше предыдущего
    pi.StartNewAction 85, 90, "Действие 4"    ' начинается через время после предыдущего
    pi.StartNewAction 10, 100, "Действие 5"    ' начинаем почти всё сначала

 

По окончании макроса желательно закрыть прогресс бар:

pi.Hide    ' закрываем индикатор

 

 

У объекта ProgressIndicator имеется много различных свойств и методов.

 

Вкратце расскажу о некоторых свойствах:

  • свойство Caption позволяет задать новый заголовок индикатора
  • свойство FP позволяет получить доступ к отображаемой форме (и всем её элементам управления)
    (например, код pi.FP.PrintForm выведет индикатор на печать)
  • свойства Line1Line2 и Line3 позволяют в любом месте кода задать текст конкретной строки индикатора
  • свойства ShowPercents и ShowTime включают или выключают отображение процента выполнения и времени в заголовке индикатора
    (по умолчанию оба свойства имеют значение TRUE, т.е. в заголовке отображается и время, и процент выполнения макроса)

 

Из функций объекта мы рассмотрим только одну: AddChildIndicator

Эта функция создаёт дочерний прогресс бар, и отображает его выше или ниже родительского:

' создаём дочерний индикатор, и выводим его ниже основного
    Dim pi2 As ProgressIndicator
    Set pi2 = pi.AddChildIndicator("Раскрашивание ячеек", 1)

При изменении процента выполнения в дочернем индикаторе пропорционально меняется и процент выполнения главного (родительского) прогресс-бара.

 

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

 

На индикаторе присутствует кнопка «Отмена» - её нажатие вызывает останов всех запущенных макросов
(выполняется команда End, останавливающая все макросы, и обнуляющая все переменные)

Поскольку у этой кнопки свойство Cancel установлено в TRUE, нажатие на клавиатуре клавиши ESC равносильно нажатию кнопки «Отмена»
(при нажатии Esc макрос останавливается)

 


добавлено 23.02.2012

Новая версия прогресс-бара - с поддержкой отображения лога на индикаторе, и возможностью отображения лога в виде текстового файла.

новая версия прогресс-бара

 

Высоту текстового поля с логом можно изменять:

вывод лога макроса на индикаторе выполнения

Новая  версия индикатора, и примеры его использования - во втором прикреплённом файле.


PS: Идеальный прогресс-бар должен работать так :)

Вложения:

Комментарии

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

В случае Option Explicit к кому типу данных отнести:

dim ИменаМакросов(4) As ... (?)
dim macro As Object (?)

Я бы использовал такой способ:
(если внутри вызываемых макросов не надо отображать ход действий на индикаторе)

Sub test()
    ИменаМакросов = Array("Макрос1", "Макрос2", "Макрос9", "Макрос10")
 
 
    Dim pi As New ProgressIndicator
    pi.Show "Выполнение нескольких макросов без циклов"
    pi.StartNewAction , , , , , UBound(ИменаМакросов) + 1
 
    For Each macro In ИменаМакросов
        pi.SubAction "Выполняется макрос «" & macro & "»"
        Run macro ' собственно, запуск макроса с заданным именем
    Next
 
    pi.Hide
End Sub
 
Sub Макрос1(): Application.Wait Now + 2 / 86400: End Sub
Sub Макрос2(): Application.Wait Now + 2 / 86400: End Sub
Sub Макрос9(): Application.Wait Now + 2 / 86400: End Sub
Sub Макрос10(): Application.Wait Now + 2 / 86400: End Sub

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

Как использовать Ваш pi, для индикации следующего Макроса:

Начало Основного макроса_0
' внутри следуют вызов макросов)
Call макрос 1 (вложенный)- не имеет "явного" цикла (например: внутри выполняется код автофильтрация продолжительностью на 1..2 мин и т.п.)
Call макрос 2 (вложенный)- не имеет "явного" цикла (типа мактоса 1)
Call макрос 3 (вложенный)- не имеет "явного" цикла
...
Call макрос N (вложенный)- не имеет "явного" цикла
Конец Основного макрос_0

Что посоветуете?

Прогресс-бар может работать с абсолютно любым макросом, и неважно, что делает этот макрос.
Пока работает ваш макрос - индикатор будет отображать ход его выполнения.

Добрый день, он будет работать с макросом который заполняет Workbook данными из других Excel и Notepad файлов в различные листы этой книги сопряжённое с copy-paste этих данных. Причем с документами работает не как с объектами, а прямым запуском и последующим закрытием (когда писал макрос была сложность с объектно-ориентированным программированием в среде VBA, а сейчас как-то лень и времени нет перебирать весь код)

и на этом спасибо.

Ускорить автофильтры вам могут помочь на форумах по Excel, если вы обратитесь туда за советом.
Если оптимизировать код - он и работать будет в десятки раз быстрее, и строк заметно поубавится.
Но мне некогда разбираться в этом коде. Проще написать всё заново, без оглядки на этот код.

 

не могли бы Вы дать несколько разъяснений как (чем) заменить ненужные Select и Activate

А поиском воспользоваться вам религия не позволяет?

Десятки раз объяснял людям на форумах, как и зачем это делается...

 

Это ещё не весь макрос. Этот макрос отвечает только за формирование таблицы.
Выполняется макрос относительно не долго - около 5 минут.
Ниже 1/4 макроса для применения различных автофильтров.
Дольше всего происходит применение автофильтра :( а как ускорить автофильтр я не знаю.
У каждого макроса есть своя клавиша для применения.
 
<Здесь был гигабайт кода, который я удалил \\ EducatedFool>

Макрос написал сам.
Вся проблема в том, что я самоучка в написании макросов и учусь их писать всего около месяца. (хочется облегчить (автоматизировать) свою работу).
Я просто не знаю чем (как) заменить ненужные Select и Activate. Знаю что есть встроенные функции типа "IF" или "With", но не знаю как их применить. Некоторые задачи решаю путём поиска в интернете макросов в формате " XXX - ваш макрос - XXX". Также имеются сложности в определении основного макроса и вспомогательного.
Если Вас не затруднит, то не могли бы Вы дать несколько разъяснений как (чем) заменить ненужные Select и Activate и ускорить работу макроса. А также как узнать способы применения встроенных функций (может сайт какой-то есть для самоучек, где в понятном формате всё можно узнать).

Владимир, тут не прогресс-бар надо прикручивать, а код оптимизировать
(например, убрать все ненужные Select и Activate)

Сколько времени продолжается работа вашего кода?

 

PS: Пример вставки прогресс-бара есть в статье.

Если вы сами этот огромный макрос написали - без проблем добавите ещё 7-8 строк

(по аналогии с моим примером)

Что именно не получается?

Подскажите пожалуйста как использовать индикатор выполнения в моём макросе, куда вставить? (ответ если можно в почту Vladimir040185@ya.ru):

... ' тут был километр кода (удалено)

Понял, исправил, все чудесно работает спасибо Вам!

Прогресс-бар замедляет работу макроса лишь потому, что вы забыли убрать "тормоза" из кода:

' Пауза, чтобы были видны изменения на прогресс-баре
For i = 1 To 500: DoEvents: Next

В моём примере эта задержка нужна потому, что без неё макрос выполнится слишком быстро, и вы даже не успеете заметить, что отображалось на экране (я добавил задержку лишь в демонстрационных целях)

Попробуйте такой код:

Sub СкрытиеСтрок()
Dim n As long
 
' создаём новый прогресс-бар
Dim pi As New ProgressIndicator
pi.Show "Обработка данных"
 
КоличествоЯчеек = 168
' устанавливаем начальное и конечное подожение индикатора для текущего действия
pi.StartNewAction 0, 100, "Скрытие строк", , , КоличествоЯчеек
 
For n = 12 To 180
If Application.CountA(Range("C:C").Rows(n)) = 0 Then Rows(n).EntireRow.Hidden = True
' отображаем на прогресс-баре текущее действие
pi.SubAction , "Скрываем строку " & n
Next n
 
pi.Hide ' закрываем основной индикатор
End Sub

Вообще, этот код можно выполнить за долю секунды, если использовать специально предназначенный для этого макрос, и не использовать ненужный данном случае прогресс-бар:
http://excelvba.ru/code/ConditionalRowsDeleting

Отличная вещь! спасибо! Только подскажите пожалуйста почему визуализация замедляет работу макроса? При использовани прогресс-бара работа макроса увеличивается до 4х минут, а без него занимает несколько секунд... И макрос вроде не сложный:

Sub ПримерИспользованияПрогрессБара()
Dim n As Byte

' создаём новый прогресс-бар
Dim pi As New ProgressIndicator
pi.Show "Обработка данных": pi.ShowPercents = True

КоличествоЯчеек = 168
' устанавливаем начальное и конечное подожение индикатора для текущего действия
pi.StartNewAction 0, 100, "Скрытие строк", , , КоличествоЯчеек

For n = 12 To 180 Step 1
If Application.CountA(Range("C:C").Rows(n)) = 0 Then Rows(n).EntireRow.Hidden = True
' отображаем на прогресс-баре текущее действие
pi.SubAction , "Скрываем строку " & Rows(n).Row
' Пауза, чтобы были видны изменения на прогресс-баре
For i = 1 To 500: DoEvents: Next
Next n

pi.Hide ' закрываем основной индикатор
End Sub

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
CAPTCHA
Подтвердите, пожалуйста, что вы - человек:
   __     _   _  __   ___           _     
/ /_ | | | |/ / / _ \ ___ | |
| '_ \ | | | ' / | (_) | / _ \ | |
| (_) | | | | . \ \__, | | __/ | |___
\___/ |_| |_|\_\ /_/ \___| |_____|
Введите код, изображенный в стиле ASCII-арт.

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

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