É importante que um programa dê feedback visual ao usuário a respeito da execução de um processo longo. Por exemplo, durante a realização de cálculos demorados, o Excel mostra ao usuário o progresso dos cálculos:
Se você desenvolve macros que executam cálculos e análises demoradas, é recomendável criar um feedback visual semelhante. Esta página ensina como mostrar ao usuário o progresso de uma tarefa na barra de status do Excel durante a execução de uma macro.
Introdução
Numa pasta de trabalho (vá até o final da página para baixá-la), há uma planilha com uma tabela como a mostrada abaixo:
Essa planilha tem aproximadamente 20.000 linhas e nela há uma macro que preenche os valores de impostos das colunas vizinhas, de acordo com critérios que não possuem relevância aqui.
O processo, como todo, é demorado. Então, criei uma barra de progresso que é mostrada na barra de status do Excel durante a execução do processo:
Código
O código completo, que deve estar num módulo regular, é mostrado abaixo:
Option Explicit Private Sub DemoStatusBar() Dim i As Long Dim iStep As Long Dim iValue As Double Dim TotalSteps As Long wsData.Range("C3:F20000").ClearContents 'Configurar qual o máximo da barra de progresso 'Regra geral: [Maior valor] - [Menor valor] + 1 TotalSteps = 20000 - 3 + 1 For i = 3 To 20000 iValue = wsData.Cells(i, "B").Value2 wsData.Cells(i, "C") = iValue * WorksheetFunction.RandBetween(2, 5) / 100 wsData.Cells(i, "D") = iValue * WorksheetFunction.RandBetween(7, 10) / 100 wsData.Cells(i, "E") = iValue * WorksheetFunction.RandBetween(12, 15) / 100 wsData.Cells(i, "F") = iValue * WorksheetFunction.RandBetween(17, 20) / 100 'Só queremos que a execução entre neste bloco de código algumas vezes If i Mod 100 = 0 Then 'Como o primeiro passo se dá quando i = 3, devemos ajustar o valor do passo 'subtraindo-se 2 iStep = i - 2 SetProgressBar iStep, TotalSteps 'Use DoEvents para desafogar os processos pendentes do Excel e não permitir travá-lo DoEvents End If Next i 'Volte a barra de status do Excel para o normal: Application.StatusBar = False End Sub Sub SetProgressBar(pStep As Long, pTotalSteps As Long) Const MAX_WIDTH As Long = 40 Dim ProgressBar As String Dim CompletedProgress As String Dim MissingProgress As String CompletedProgress = WorksheetFunction.Rept("|", pStep / pTotalSteps * MAX_WIDTH) MissingProgress = WorksheetFunction.Rept(" ", MAX_WIDTH - Len(CompletedProgress)) ProgressBar = CompletedProgress & MissingProgress ProgressBar = "[ " & ProgressBar & " ]" ProgressBar = ProgressBar & " " & Format(pStep / pTotalSteps, "0%") Application.StatusBar = ProgressBar End Sub
Para definir visualmente o progresso de uma barra precisamente, é necessário saber qual é o passo que um determinado processo se encontra e quantos passos são necessários. O número total de passos pode ser calculado, normalmente, através da pseudofórmula:
TotalPassos = ValorFinal - ValorInicial + 1
Note que ValorInicial
não corresponde, necessariamente, ao valor inicial que a variável de controle assume no laço. No nosso laço, i
começa em 3
e vai até 20000
. Então, temos um total de 20000 - 3 + 1 = 19998
passos no total e a variável iStep
vai, consequentemente, de 1
a 19998
.
Para definir a barra de progresso num passo, criei o subprocedimento SetProgressBar
. Ela monta uma cadeia de texto que calcula quantos |
(pipe) e espaços em branco devem ser mostrados de acordo com o valor de pStep
em relação a pTotalSteps
nas variáveis CompletedProgress
e MissingProgress
, respectivamente. Por fim, concatena essas variáveis, concatena o percentual do progresso e atribui o valor da cadeia de texto na barra de status do Excel.
No laço, a condição If i Mod 100 = 0 Then
faz com que seu bloco de código seja executado apenas quando i
for um múltiplo de 100
. Pelo fato do laço rodar várias vezes (19998
, para ser mais exato), é desnecessário atualizar a barra de progresso todas as vezes porque, caso contrário, o desempenho da rotina seria prejudicado. Limitar de 100
em 100
, mesmo que arbitrariamente, é uma boa prática.
Da mesma forma, a instrução DoEvents
não precisa ser executada todas as 19998
vezes. Aproveitei o bloco de código do teste condicional para inserí-lo também. Cabe a você decidir se ela fica fora do subprocedimento de atualização da barra de progresso ou não.
Ao final da rotina, atribui-se Application.StatusBar = False
para que a barra de status do Excel volte ao normal.
Download
Para fazer download da pasta de trabalho usada neste artigo, clique aqui.