Хитрости »
26 Февраль 2016 56344 просмотров
Отобразить процесс выполнения
Часто при создании кодов в VBA используется обращение к ячейкам, листам, книгам и т.д. и их обработка в циклах. Пара примеров подобных циклов:
- Просмотреть все файлы в папке — цикл по файлам в папке — Do While sFiles <> «» и For Each objFile In objFolder.Files
- Массовая замена слов — цикл по ячейкам(массивам) — For lr = 1 To UBound(avArr, 1)
- Не работают/пропали меню — цикл по всем панелям — For Each cmdBar In Application.CommandBars
Если операция в цикле выполняется за пару секунд — это вполне приемлемо и отражать графически подобные действия нет нужды. Но, если циклы «крутятся» по полчаса — вполне неплохо иметь возможность видеть на какой стадии цикл. Здесь есть один нюанс: циклы могут быть как с заранее известным кол-вом итераций, так и без этого понимания.
Цикл Do While из первого кода статьи Просмотреть все файлы в папке является циклом условия. Т.е. заранее неизвестно сколько файлов будет обработано и следовательно невозможно отразить прогресс выполнения задачи в процентах.
Циклы вроде For Each и For … Next как правило дают возможность определить общее кол-во элементов к обработке, т.к. применяются как правило к коллекциям и объектам, у которых есть свойство .Count. Углубляться в этой статье не стану — это лишь предисловие, чтобы было ясно, почему и зачем далее в статье продемонстрированы разные подходы отображения процесса выполнения.
Отобразить же процесс можно двумя способами:
- Использование Application.StatusBar
- Использование UserForm
Использование Application.StatusBar
Самый простой вариант отображения процесса выполнения кода. Он может быть без проблем использован на любом ПК.
Application.StatusBar
— это специальный элемент интерфейса, расположенный в левой нижней части окна Excel и который может показывать дополнительную информацию в зависимости от действий пользователя. Все не раз видели его в работе. Например, после того как мы скопировали ячейки StatusBar покажет нам доп.информацию:
И из VBA есть доступ к этому элементу. Чтобы написать слово привет в StatusBar надо выполнить всего одну строку кода:
Application.StatusBar = "Привет"
Чтобы сбросить значения StatusBar и передать управление им обратно самому Excel необходимо выполнить строку:
Application.StatusBar = False
делать это обязательно, т.к. в противном случае вместо системных доп.сообщений будет постоянно показываться то значение, которое мы задали. Конечно, можно перезапустить Excel, но куда правильнее дописать в код строку, приведенную выше.
Как я уже упоминал — циклы могут быть с заранее неизвестным кол-вом итераций. В таких случаях очень удобно показывать стадию выполнения хотя бы из тех побуждений, чтобы пользователь видел, что программа не «зависла». на примере кода из статьи Просмотреть все файлы в папке:
Sub Get_All_File_from_Folder() Dim sFolder As String, sFiles As String 'диалог запроса выбора папки с файлами With Application.FileDialog(msoFileDialogFolderPicker) If .Show = False Then Exit Sub sFolder = .SelectedItems(1) End With sFolder = sFolder & IIf(Right(sFolder, 1) = Application.PathSeparator, "", Application.PathSeparator) 'отключаем обновление экрана, чтобы наши действия не мелькали Application.ScreenUpdating = False sFiles = Dir(sFolder & "*.xls*") Do While sFiles <> "" 'показываем этап выполнения Application.StatusBar = "Обрабатывается файл '" & sFiles & "'" 'открываем книгу Workbooks.Open sFolder & sFiles 'действия с файлом 'Запишем на первый лист книги в ячейку А1 - www.excel-vba.ru ActiveWorkbook.Sheets(1).Range("A1").Value = "www.excel-vba.ru" 'Закрываем книгу с сохранением изменений ActiveWorkbook.Close True 'если поставить False - книга будет закрыта без сохранения sFiles = Dir Loop 'возвращаем ранее отключенное обновление экрана Application.ScreenUpdating = True 'сбрасываем значение статусной строки Application.StatusBar = False End Sub
Если запустить код, то перед открытием каждой книги в строке StatusBar будет показано какой именно файл отрывается и обрабатывается. И так с каждым файлом:
В случае же с циклами, количество итераций которых есть возможность определить, можно показывать этап выполнения в процентах. Например, цикл по всем выделенным ячейкам:
Sub ShowProgressBar() Dim lAllCnt As Long, lr as Long Dim rc As Range 'кол-во ячеек в выделенной области lAllCnt = Selection.Count 'цикл по всем ячейкам в выделенной области For Each rc In Selection 'прибавляем 1 при каждом шаге lr = lr + 1 Application.StatusBar = "Выполнено: " & Int(100 * lr / lAllCnt) & "%" DoEvents 'чтобы форма перерисовывалась Next 'сбрасываем значение статусной строки Application.StatusBar = False End Sub
В строке статуса это будет выглядеть так:
Но можно показывать информацию и в чуть более изощренных формах:
Вариант отображения % и блоками-цифрами от 1 до 10(1 = 10% выполнения)
Sub StatusBar1() Dim lr As Long, lrr As Long, lp As Double Dim lAllCnt As Long 'кол-во итераций Dim s As String lAllCnt = 10000 'основной цикл For lr = 1 To lAllCnt lp = lr 100 'десятая часть всего массива s = "" 'формируем строку символов(от 1 до 10) For lrr = 10102 To 10102 + lp 10 s = s & ChrW(lrr) Next 'выводим текущее состояние выполнения Application.StatusBar = "Выполнено: " & lp & "% " & s: DoEvents DoEvents Next 'очищаем статус-бар от значений после выполнения Application.StatusBar = False End Sub
Вариант отображения % и стрелками ->(1 стрелка = 10% выполнения)
Sub StatusBar2() Dim lr As Long, lp As Double Dim lAllCnt As Long 'кол-во итераций Dim s As String lAllCnt = 10000 For lr = 1 To lAllCnt lp = lr 100 'десятая часть всего массива 'формируем строку символов(от 1 до 10) s = String(lp 10, ChrW(10152)) & String(11 - lp 10, ChrW(8700)) Application.StatusBar = "Выполнено: " & lp & "% " & s: DoEvents DoEvents Next 'очищаем статус-бар от значений после выполнения Application.StatusBar = False End Sub
Вариант отображения % и квадратами (кол-во квадратов можно изменять. Если lMaxQuad=20 — каждый квадрат одна 20-я часть всего массива)
Sub StatusBar3() Dim lr As Long Dim lAllCnt As Long 'кол-во итераций Const lMaxQuad As Long = 20 'сколько квадратов выводить lAllCnt = 10000 For lr = 1 To lAllCnt Application.StatusBar = "Выполнено: " & Int(100 * lr / lAllCnt) & "%" & String(CLng(lMaxQuad * lr / lAllCnt), ChrW(9632)) & String(lMaxQuad - CLng(lMaxQuad * lr / lAllCnt), ChrW(9633)) DoEvents Next 'очищаем статус-бар от значений после выполнения Application.StatusBar = False End Sub
Этот вариант мне нравится больше всего.
При желании можно сделать и иные варианты — главное найти символы, которые будут показываться и определить их числовой код.
Использование UserForm
Использование стандартного элемента ProgressBar
Для Userform можно использовать стандартный контрол ProgressBar, но я лично не люблю добавлять на формы элементы, которые надо подключать отдельно. Потому как впоследствии контрол может отказаться работать, т.к. нужной версии не окажется на конечном ПК пользователя. Например в моем офисе 2010 для 64-битных систем его нет.
Поэтому про него кратко и в файле примере его нет. Как его создать:
- создаем UserForm (в меню VBE —Insert —UserForm. Подробнее про вставку модулей и форм — Что такое модуль? Какие бывают модули?)
- отображаем окно конструктора(если не отображено): View —Toolbox
- далее в меню Tools —Additional Controls
- там ищем что-то имеющее в названии ProgressBar и отмечаем его. Жмем Ок.
Теперь в окне Toolbox появится элемент ProgressBar. Просто перетаскиваем его на форму. В свойствах можно задать цвет и стиль отображения полосы прогресса. Останется лишь при необходимости программно показывать форму и задавать для элемента ProgressBar значения минимума и максимума. Примерно это выглядеть будет так:
Практический код
Например, надо обработать все выделенные ячейки. Если форма называется UserForm1, а ProgressBar — ProgressBar1, то код будет примерно такой:
Sub ShowProgressBar() Dim lAllCnt As Long Dim rc As Range 'кол-во ячеек в выделенной области lAllCnt = Selection.Count 'показываем форму прогресс-бара UserForm1.Show UserForm1.ProgressBar1.Min = 1 UserForm1.ProgressBar1.Max = lAllCnt 'цикл по всем ячейкам в выделенной области For Each rc In Selection 'прибавляем 1 при каждом шаге UserForm1.ProgressBar1.Value = UserForm1.ProgressBar1.Value + 1 DoEvents 'чтобы форма перерисовывалась Next 'закрываем форму Unload UserForm1 End Sub
Использование своего собственного прогресс-бара
Я использую в своих приложениях свой прогресс-бар с процентами. Для этого я использую стандартную UserForm, на которой располагаю два элемента Caption. Первый отвечает за визуальную составляющую в виде синей полосы заполнения, а так же за отображение процентов белыми цифрами на синем фоне. Второй Caption прозрачный и на нем в том же месте, что и у первого, отображаются проценты цифрами, но уже черным шрифтом. В результате в работе это выглядит так:
Как использовать эту форму и коды
Первоначально надо скачать файл, приложенный к статье, и в свой проект перенести форму frmStatusBar и модуль mCustomProgressBarModule.
Далее просто внедряем нужные строки в свои коды с циклами:
- До начала цикла необходимо вызывать процедуру инициализации формы:
Call Show_PrBar_Or_No(lAllCnt, «Обрабатываю данные…»)
первым аргументом задается общее кол-во обрабатываемых элементов, а вторым заголовок формы. Если второй аргумент не указан, то по умолчанию будет показан заголовок «Выполнение…». Так же внутри кодов есть кусок кода, отвечающий за минимальное кол-во элементов к обработке. По умолчанию задано 10. Это значит, что если обрабатывается менее 10 ячеек, то форма прогресс-бара показана не будет. Нужно для случаев, когда производятся разные действия над ячейками, но неизвестно сколько их будет. Но зато известно, что с ними будет делать код. Часто для кол-ва ячеек менее 100 нет смысла отображать прогресс выполнения, т.к. это и так секундное дело.
Чтобы изменить минимальное кол-во достаточно в строке bShowBar = (lCnt > 10) заменить 10 на нужное число. - Далее в каждом проходе цикла вызвать перерисовку формы под новое значение цикла:
If bShowBar Then Call MyProgresBar - и в конце не забыть закрыть форму, чтобы не висела:
If bShowBar Then Unload frmStatusBar
Пример применения формы:
Sub Test_ProgressForm() Dim lr As Long Dim lAllCnt As Long 'кол-во итераций lAllCnt = 10000 'инициализируем форму прогресс-бара Call Show_PrBar_Or_No(lAllCnt, "Обрабатываю данные...") 'сам цикл For lr = 1 To lAllCnt If bShowBar Then Call MyProgresBar Next 'закрываем форму, если она была показана If bShowBar Then Unload frmStatusBar End Sub
Так же все описанные примеры и коды можно найти в приложенном файле:
Скачать пример:
Tips_ShowProgressBar.xls (79,0 KiB, 6 153 скачиваний)
Статья помогла? Поделись ссылкой с друзьями!
Видеоуроки
Поиск по меткам
Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика
Home / VBA / VBA Status Bar (Hide, Show, and Progress)
In VBA, there’s a “Status Bar” property that can help you to show a value to the status bar and there’s also “DisplayStatusBar” to hide and show the status from the Excel window. While using these properties you need to reset the status bar, at the end, otherwise, the last message or setting will stay there.
In the tutorial, we will see a few examples that we can use while working in Excel.
Show a Value on the Status Bar
As I said, you can use the StatusBar property to show a value to the status bar. In the below code, you have used the value “Hello” to add to the status bar.
- Use the keyword “Application” to refer to the Excel application.
- Type a dot to get the list of properties and methods.
- Select the “StatusBar” property.
- In the end, use the equals sign to specify the value you want to display on the status bar.
Sub vba_status_bar()
Application.StatusBar = "Hello"
End Sub
Hide the Status Bar using VBA
Now let’s say if you want to hide the status bar you can use the DisplayStatusBar and specify that property to the “False” (consider the following code).
- Use the keyword “Application” to refer to the Excel application.
- Type a dot to get the list of properties and methods.
- Select the “DisplayStatusBar” property.
- In the end, use the equals sign to specify the “False”.
Sub vba_status_bar_hide()
Application.DisplayStatusBar = False
End Sub
Update Progress on Status Bar
The following code runs show a progress counter on the status bar using the count 1 to 100, which you can change as per your need.
Sub vba_status_bar_update()
Dim x As Integer
Dim iTimer As Double
'you can change the loop if you need
For x = 1 To 100
'dummy loop to run, you can change it as well
iTimer = Timer
Do
Loop While Timer - MyTimer < 0.03
Application.StatusBar = "Progress: " & x & " of 100: " & Format(x / 100, "Percent")
DoEvents
Next x
Application.StatusBar = False
End Sub
Important Points to Remember
- You need to use the “Application” with the status bar properties to use them.
- Once you show a message on the status you need to clear that message.
There’s More
VBA With Statement | VBA Wait and Sleep Commands | VBA ScreenUpdating | VBA Random Number | Line Break in a VBA Code | VBA Immediate Window (Debug.Print) | VBA Concatenate | VBA Module | VBA Random Number
Excel VBA StatusBar
StatusBar is the property of a VBA one may use to display the status of the completed code at the time of execution. For example, it displays at the left-hand side corner of the worksheet when a Macro executes. The status shows in percentage to the user.
When the Macro is running behind, it is frustrating to wait without knowing how long it will take. But, if you are at the stage where the code is running, you can at least calculate the time it will take. So, the idea is to have a status barAs the name implies, the status bar displays the current status in the bottom right corner of Excel; it is a customizable bar that can be customized to meet the needs of the user.read more showing the percentage of work completed so far, like the one below.
Table of contents
- Excel VBA StatusBar
- What is Application.StatusBar?
- Example to Create StatusBar using VBA
- Things to Remember
- Recommended Articles
What is Application.StatusBar?
The Application.StatusBar is the property we can use in macro coding to show the status when the Macro is running behind the scenes.
It is not as beautiful as our “VBA Progress Bar” but good enough to know the status of the Macro project.
You are free to use this image on your website, templates, etc, Please provide us with an attribution linkArticle Link to be Hyperlinked
For eg:
Source: VBA StatusBar (wallstreetmojo.com)
Example to Create StatusBar using VBA
You can download this VBA Status Bar Excel Template here – VBA Status Bar Excel Template
Follow the below steps to create a status bar.
Step 1: First, define the VBA variableVariable declaration is necessary in VBA to define a variable for a specific data type so that it can hold values; any variable that is not defined in VBA cannot hold values.read more to find the last used row in the worksheet.
Code:
Sub Status_Bar_Progress() Dim LR As Long End Sub
Step 2: Find the last used row using the below code.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row End Sub
Step 3: Next, we need to define the variable to hold the number of bars to be displayed.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer End Sub
It will hold how many bars are allowed to show in the status bar.
Step 4: For this variable, store the limit of the bar as 45.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 End Sub
Step 5: Define two more variables to hold the current status and percentage completed when the Macro runs.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer End Sub
Step 6: Now, use the code below to enable the status bar.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" End Sub
What this will do is add the bracket ([) and add 45 spaces characters before ending the text with the closing bracket (]).
Execute the code. See the below in the Excel VBA status bar.
Output:
Step 7: We need to include the For Next loop in VBAAll programming languages make use of the VBA For Next loop. After the FOR statement, there is a criterion in this loop, and the code loops until the criteria are reached. read more to calculate the percentage of the completed Macro. Then, define a variable to start the Macro.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR Next k End Sub
Step 8: Inside the loop, we need to calculate the “Present Status.” So, for the variable “PresentStatus,” we need to apply the formula below.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) Next k End Sub
We have used the INT function to get the integer value.
Step 9: We need to calculate the “Percentage Completion” to apply the formula shown below.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Next k End Sub
In this case, we have used the ROUND function in Excel because we need to round to the nearest zero value, whatever the decimal places. So, ROUND with zero as the argument used here.
Step 10: We have already inserted the starting bracket and end bracket into the status bar, now we need to insert the updated result, and it can be done by using the below code.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus) & _"] " & PercetageCompleted & "% Complete" Next k End Sub
In the above code, we have inserted the opening bracket “[“and to show the progress of the Macro, we have inserted a straight line (|) by using the STRING function. When the loop runs, it will take the “PresentStatus.” It will insert those many straight lines in the status bar.
Code:
Application.StatusBar = "[" & String(PresentStatus, "|")
Next, we need to add space characters between one straight line and the other, which will calculate using “NumOfBars” minus “PresentStatus.”
Code:
Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus)
Then, we close out the bracket “].” Next, we have combined the “PercentageCompleted” variable value while the loop runs with the word in front of it as “% Completed.”
Code:
Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus)& _"] " & PercetageCompleted & "% Complete"
When the code runs, we allow the user to access the worksheet, so we need to add “Do Events.”
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus) & _ "] " & PercetageCompleted & "% Complete" DoEvents Next k End Sub
Step 11: After adding “Do Events,” we can write the codes that need to execute here.
For example, we want to insert serial numbers into the cells, so we will write the code below.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus) & _"] " & PercetageCompleted & "% Complete" DoEvents Cells(k, 1).Value = k 'You can add your code here Next k End Sub
Step 12: Before we come out of the loop, we need to add one more thing, i.e., If the loop is near the last used row in the worksheet, then we need to make the status bar normal.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus) & _"] " & PercetageCompleted & "% Complete" DoEvents Cells(k, 1).Value = k 'You can add your code here 'You can Add your code here 'You can Add your code here 'You can add your code here 'You can add your code here 'You can add your code here If k = LR Then Application.StatusBar = False Next k End Sub
We have completed the coding. As you execute the code, you can see the status bar updating its percentage completion status.
Output:
Below is the code for you.
Code:
Sub Status_Bar_Progress() Dim LR As Long LR = Cells(Rows.Count, 1).End(xlUp).Row Dim NumOfBars As Integer NumOfBars = 45 Dim PresentStatus As Integer Dim PercetageCompleted As Integer Application.StatusBar = "[" & Space(NumOfBars) & "]" Dim k As Long For k = 1 To LR PresentStatus = Int((k / LR) * NumOfBars) PercetageCompleted = Round(PresentStatus / NumOfBars * 100, 0) Application.StatusBar = "[" & String(PresentStatus, "|") & Space(NumOfBars - PresentStatus) & _"] " & PercetageCompleted & "% Complete" DoEvents Cells(k, 1).Value = k 'You can add your code here 'You can Add your code here 'You can Add your code here 'You can add your code here 'You can add your code here 'You can add your code here If k = LR Then Application.StatusBar = False Next k End Sub
Things to Remember
- We can add only the tasks we need to do within the loop.
- After adding the “Do Events” procedure, we can add the tasks you need to do.
Recommended Articles
This article has been a guide to VBA StatusBar. Here, we discuss enabling the status bar to show progress using VBA code in Excel, a practical example, and a downloadable template. Below you can find some useful Excel VBA articles: –
- Barcode in Excel
- ListObjects in VBA
- VBA Find Next
- CDEC in VBA
Ранее я рассмотрел методы создания пользовательских форм и основы работы с ними (если вы никогда не работали с пользовательскими формами, рекомендую для начала прочитать указанную заметку). В настоящей заметке показано использование индикатора текущего состояния – графического «измерителя», который отображает текущее состояние выполняемой задачи, например, долго работающего макроса.[1]
Рис. 1. В окне UserForm отображается ход выполнения макроса
Скачать заметку в формате Word или pdf, примеры в архиве
Мы рассмотрим три метода создания индикаторов текущего состояния:
- Макрос, который запускается за пределами диалогового окна UserForm (отдельный индикатор текущего состояния).
- Макрос, который запускается из диалогового окна UserForm. При этом в диалоговом окне UserForm используется элемент управления MultiPage для отображения индикатора текущего состояния, пока выполняется другой макрос.
- Макрос, который запускается из диалогового окна UserForm. При этом высота диалогового окна UserForm увеличивается, а индикатор текущего состояния отображается в нижней части окна.
При использовании индикатора текущего состояния необходимо знать, насколько завершено текущее задание. Способы получения этой информации различаются в зависимости от типа выполняемого макроса. Например, если макрос записывает данные в ячейки (и количество таких ячеек известно), то остается создать код, который будет подсчитывать процентное отношение количества ячеек, содержащих данные. Даже если невозможно точно оценить, насколько далеко «зашел» макрос, пользователю небезынтересно будет узнать, что макрос еще выполняется и Excel не завис.
Отображение индикатора текущего состояния в строке состояния окна
Простой способ отображения хода выполнения макроса — использование строки состояния Excel. Его преимущество — простота реализации. Недостатком же является то, что большинство пользователей не привыкли отслеживать информацию, которая отображается в строке состояния окна, поскольку предпочитают просматривать ее в отдельном окне.
Для отображения сообщения в строке состояния используется следующий оператор:
Application.StatusBar = "
Пожалуйста, подождите…"
Можно обновлять строку состояния в процессе выполнения макроса. Например, если в макросе используется переменная Pet, которая представляет состояние задачи, можно создать код, который будет периодически выполнять следующий оператор:
Application.StatusBar = "
Выполнение… "
&Pet&"
% завершено"
После завершения макроса нужно вернуть строку состояния к прежнему виду. Для этого используется следующий оператор:
Application.StatusBar = False
Если строка состояния не возвращена к прежнему виду, продолжает отображаться завершающее сообщение. Помните о том, что индикатор текущего состояния замедляет выполнение макроса, поскольку обновление индикатора требует дополнительного использования системных ресурсов. Если быстродействие макроса превыше всего, от использования индикатора текущего состояния лучше отказаться.
Создание отдельного индикатора текущего состояния
Такой индикатор не инициализируется путем отображения формы UserForm. Следующий макрос очищает рабочий лист, и записывает 20 тысяч случайных чисел в диапазон ячеек (см. также файл progress indicatorl.xlsm).
Sub GenerateRandomNumbers() ‘ Вставка случайных чисел на активный лист Const RowMax As Long = 500 Const ColMax As Long = 40 Dim r As Long, c As Long If TypeName(ActiveSheet) <> «Worksheet» Then Exit Sub Cells.Clear For r = 1 To RowMax For c = 1 To ColMax Cells(r, c) = Int(Rnd * 1000) Next c Next r End Sub |
После небольшого изменения макроса (описанного в следующем разделе) диалоговое окно UserForm отображает индикатор процесса выполнения макроса (рис. 1).
Создание диалогового окна UserForm, включающего индикатор текущего состояния
Выполните следующие шаги:
- Вставьте новое диалоговое окно UserForm и измените значение свойства Caption на Ход выполнения процесса.
- Добавьте элемент управления Frame и присвойте ему имя FrameProgress.
- Добавьте элемент управления Label в состав элемента управления Frame и назначьте ему имя LabelProgress. Удалите заголовок этого элемента управления, а также сделайте его фон красным (посредством свойства BackColor). На данный момент размеры и расположение этого элемента управления не важны.
- Добавьте еще один элемент управления Label над элементом управления Frame, с помощью которого вы будете описывать происходящее (необязательно). В нашем примере с помощью этого элемента управления добавляется надпись Ход выполнения процесса.
- Настройте диалоговое окно UserForm и элементы управления таким образом, чтобы они выглядели, как на рис. 2.
Рис. 2. Окно формы UserForm может играть роль индикатора хода выполнения процесса
Можно изменить тип форматирования элементов управления. Например, свойство SpecialEffect элемента Frame таким образом, чтобы последний стал «вдавленным».
Создание процедур обработки событий. Важно, чтобы процедура автоматически запускалась при отображении диалогового окна UserForm. Один из вариантов подразумевает использование события Initialize. Но это событие возникает еще до того, как диалоговое окно отображается на экране, поэтому такой вариант не подходит. С другой стороны, событие Activate возникает в тот момент, когда диалоговое окно UserForm отображается на экране, поэтому в данном случае можно остановиться на его использовании.
Вставьте следующую процедуру в модуль кода диалогового окна UserForm. Эта процедура всего лишь вызывает процедуру GenerateRandomNumbers, когда диалоговое окно UserForm отображается на экране. Процедура GenerateRandomNumbers, которая хранится в модуле кода VBA, является фактическим макросом, который будет работать, пока на экране отображается индикатор текущего состояния.
Private Sub UserForm_activate() Call GenerateRandomNumbers End Sub |
В процедуре GenerateRandomNumber имеется дополнительный модуль, который отслеживает текущее состояние, сохраняя соответствующие сведения в переменной PctDone.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Sub GenerateRandomNumbers() ‘ Вставка случайных чисел на активный лист Dim Counter As Long Const RowMax As Long = 500 Const ColMax As Long = 40 Dim r As Long, c As Long Dim PctDone As Double If TypeName(ActiveSheet) <> «Worksheet» Then Exit Sub Cells.Clear Counter = 1 For r = 1 To RowMax For c = 1 To ColMax Cells(r, c) = Int(Rnd * 1000) Counter = Counter + 1 Next c PctDone = Counter / (RowMax * ColMax) Call UpdateProgress(PctDone) Next r Unload UserForm1 End Sub |
Процедура GenerateRandomNumbers включает два цикла. Во внутреннем цикле вызывается процедура UpdateProgress, которая принимает только один аргумент (переменная PctDone, которая «ответственна» за отображение процесса выполнения макроса). Эта переменная может принимать значения от 0 до 100.
Sub UpdateProgress(Pct) With UserForm1 .FrameProgress.Caption = Format(Pct, «0%») .LabelProgress.Width = Pct * (.FrameProgress.Width — 10) .Repaint End With End Sub |
Создание процедуры запуска. Для отображения диалогового окна UserForm введите следующий код в модуль VBA.
Sub ShowUserForm() With UserForm1 ‘Использование цвета темы рабочей книги .LabelProgress.BackColor = ActiveWorkbook.Theme. _ ThemeColorScheme.Colors(msoThemeAccent1) .LabelProgress.Width = 0 .Show End With End Sub |
Можно сделать так, чтобы строка состояния соответствовала текущей теме рабочей книги. Для этого в процедуру ShowUserForm добавьте следующий оператор.
.LabelProgress.BackColor = ActiveWorkbook.Theme. _
ThemeColorScheme.Colors(msoThemeAccentl)
При выполнении процедуры ShowUserForm ширина объекта Label устанавливается равной 0. После этого вызывается метод Show объекта UserForm1, что приводит к отображению диалогового окна UserForm (которое играет роль индикатора текущего состояния). Когда диалоговое окно UserForm отображается на экране, вызывается событие Activate, которое приводит к выполнению процедуры GenerateRandomNurabers. Процедура GenerateRandomNumbers включает код, который вызывает процедуру UpdateProgress при каждом изменении переменной счетчика цикла r. Обратите внимание, что процедура UpdateProgress использует метод Repaint объекта UserForm. Если бы этого оператора не было, изображение на экране не обновлялось бы. Перед завершением процедуры GenerateRandomNumbers ее последний оператор выгружает диалоговое окно UserForm из памяти.
Для того чтобы модифицировать эту методику, необходимо разобраться, как определяется процент завершения выполняемой задачи. После этого значение состояния задачи можно будет присваивать переменной PctDone. Определение этой величины осуществляется различными способами в зависимости от приложения. Если код выполняется в цикле (как в данном примере), вычисление процента выполнения сравнительно несложное. Если же код выполняется не в цикле, определение состояния выполнения происходит в различных точках кода.
Отображение сведений о текущем состоянии с помощью элемента управления MultiPage
В предыдущем примере макрос запускался не из диалогового окна UserForm. Во многих случаях долго выполняющийся макрос можно вынудить «уйти со сцены», щелкнув мышью на кнопке ОК в диалоговом окне UserForm. В этом же разделе будет описан лучший способ, использование которого возможно при следующих допущениях:
- проект завершен и отлажен;
- в проекте используется диалоговое окно UserForm (без элемента управления MultiPage) для запуска долго выполняющегося макроса;
- существует метод оценки степени завершения выполняемой задачи.
Как и в предыдущем примере, в рабочий лист вводятся случайные числа. Отличие заключается в том, что в приложении содержится диалоговое окно UserForm, в котором пользователем определяется количество строк и столбцов для ввода случайных чисел (рис. 3; см. также файл progress indicator2.xlsm).
Рис. 3. Пользователь определяет количество строк и столбцов, в которые вводятся случайные числа
Изменение диалогового окна. На данном этапе предполагается, что диалоговое окно UserForm уже настроено. Нам осталось добавить элемент управления MultiPage. Первая страница элемента управления MultiPage будет содержать все первоначальные элементы управления. На второй странице располагаются элементы управления, которые используются для отображения индикатора текущего состояния. Когда макрос начнет выполняться, в коде VBA значение свойства Value элемента управления MultiPage изменится. В результате будут скрыты исходные элементы управления и отображены элементы управления, которые используются для создания индикатора текущего состояния.
Первым шагом будет добавление элемента управления MultiPage в диалоговое окно UserForm. После этого необходимо переместить все существующие в диалоговом окне UserForm элементы управления на первую страницу элемента управления MultiPage. Затем следует активизировать вторую страницу элемента управления MultiPage и настроить ее так, чтобы она выглядела, как показано на рис. 4. В данном случае используется та же комбинация элементов управления, что и в предыдущем примере.
- Добавьте элемент управления Frame, присвоив ему имя FrameProgress.
- Добавьте элемент управления Label в состав элемента управления Frame, присвоив ему имя LabelProgress. Удалите заголовок этого элемента управления, а также сделайте его фоновый цвет красным.
- Добавьте еще один элемент управления Label, описывающий суть происходящего (необязательно).
- Активизируйте элемент управления MultiPage в целом (а не отдельную вкладку), а свойству Style присвойте значение 2 – fmTabStyleNone. (Это приведет к сокрытию всех вкладок.) Возможно, придется изменить размер элемента управления MultiPage, чтобы учесть скрытые вкладки.
Рис. 4. Вторая вкладка элемента управления MultiPage, которая применяется для отображения индикатора текущего состояния
Простейший способ выделения элемента управления MultiPage, когда вкладки скрыты, — выбор его в раскрывающемся списке, который находится в окне Properties (подчеркнут красной линией на рис. 4). Для выбора определенной страницы укажите величину свойства Value для элемента MultiPage: 0 — для Page1, 1 — для Page2 и т.д.
Вставка процедуры UpdateProgress. Вставьте следующую процедуру в модуль кода диалогового окна UserForm.
Sub UpdateProgress(Pct) With UserForm1 .FrameProgress.Caption = Format(Pct, «0%») .LabelProgress.Width = Pct * (.FrameProgress.Width — 10) End With DoEvents End Sub |
Процедура UpdateProgress вызывается из макроса после щелчка пользователем на кнопке ОК и выполняет обновление индикатора текущего состояния.
Далее необходимо модифицировать процедуру, которая выполняется после щелчка на кнопке ОК. Данная процедура выступает обработчиком события Click и называется OKButton_Click. Для начала необходимо вставить оператор в начало процедуры:
MultiPage1.Value = 1
Этот оператор приводит к активизации второй вкладки элемента управления MultiРаgе (страницы, на которой отображается индикатор текущего состояния). На следующем шаге необходимо самостоятельно создать код, который будет вычислять степень выполнения задачи. Полученное значение следует присвоить переменной PctDone. Скорее всего, расчеты будут производиться внутри цикла. После этого нужно добавить приведенный ниже оператор, который будет обновлять индикатор текущего состояния:
Call UpdateProgress(PctDone)
Отображение индикатора текущего состояния без применения элемента управления MultiPage
Методика, рассмотренная в этом разделе, немного проще предыдущей, так как не требует применения элемента управления MultiPage. Вместо этого индикатор текущего состояния содержится в нижней части диалогового окна UserForm. Для того чтобы элементы управления, составляющие индикатор текущего состояния, изначально не были видны, высота диалогового окна UserForm была уменьшена до соответствующего размера. Как только нужно будет отобразить индикатор текущего состояния, высота диалогового окна UserForm увеличится, что сделает индикатор видимым на экране (см. файл progress indicator3.xlsm).
На рис. 5 показано диалоговое окно UserForm в редакторе VBE. Свойство Height диалогового окна UserForm имеет значение 172. Но перед тем как отобразить диалоговое окно UserForm, значение свойства Height устанавливается равным 124 (это приводит к тому, что элементы управления, представляющие индикатор текущего состояния, становятся невидимыми). Как только пользователь щелкнет на кнопке ОК, код VBA изменит значение свойства Height на 172. Для этого используется следующий оператор:
Me.Height = 172
Рис. 5. Уменьшение высоты диалогового окна UserForm приводит к сокрытию элементов управления, образующих индикатор текущего состояния
На рис. 6 показано диалоговое окно UserForm с отображенным индикатором текущего состояния.
Рис. 6. Индикатор текущего состояния в действии
[1] По материалам книги Джон Уокенбах. Excel 2010. Профессиональное программирование на VBA. – М: Диалектика, 2013. – С. 477–484.
Return to VBA Code Examples
VBA – Display Status Bar Message
At the bottom-left corner of Excel, you’ll find a Status Bar:
Excel uses this status bar to communicate messages to you. However the StatusBar Property can also be adjusted using VBA, allowing you to display your own messages.
Custom Status Bar Message
You can update the status bar with your own custom message in Excel while a macro is running, using the StatusBar property.
1. Place this code in a macro whenever you want to update the user with a custom status bar message:
Application.StatusBar = "I'm working Now!!!"
2. And at the end of your macro place this code to clear the status bar and return control back to Excel:
Application.StatusBar = FALSE
Disable Status Bar Updating
Instead of displaying a message while your procedure runs, you can disable the Status Bar. This will increase the speed of your VBA code as Excel can skip processing what Status Bar message to display.
To disable Status Bar updating while your code is running set the DisplayStatusBar property to false.
Application.DisplayStatusBar = False
At the end of your code, restore Status Bar updating:
Application.DisplayStatusBar = True
Important! Use the StatusBar property to set messages, but use the DisplayStatusBar property to disable or enable the status bar altogether.
Speed Up VBA Code
For optimal processing speed try using this code:
sub RunFast()
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
ActiveSheet.DisplayPageBreaks = False
Application.Calculation = xlCalculationManual
'Your Code Here
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
ActiveSheet.DisplayPageBreaks = True
Application.Calculation = xlCalculationAutomatic
end sub
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro – A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More!
<<Return to VBA Examples