El otro día estaba trabajando en un desarrollo en el que programé una macro que hacía muchas cosas con muchos datos. Al probarla me di cuenta de que tardaba demasiado. Desde que se le da al botón de iniciar hasta que termina puede tardar más de 5 minutos. Por supuesto, antes el trabajo se hacía a mano y se tardaba varios días. El caso es que para que el usuario no piense que Excel se ha quedado colgado, pensé en poner una barra de progreso. Tras una breve investigación en Google, resulta que la primera opción que me sale la escribió en esta misma página Quique: 6 pasos para crear una barra de progreso en Excel. Pero lo que yo necesitaba era una barra de progreso sencilla, no tenía tiempo de crear un formulario, ni de pelearme con las importaciones de referencias, etc.
Alternativas
Las alternativas que ya conocía para elaborar una barra de progreso eran
- Crear un formulario que se muestre en pantalla mientras se ejecuta la macro, actualice el valor de la barra y lo refresque en pantalla mediante un DoEvents.
- Colocar un texto en la barra de estado que indique el porcentaje de avance.
- Utilizando un control de formulario no activado por defecto, que se llama ProgressBar.
La tercera opción ni siquiera aparece en mi sistema. No sé si se habrá eliminado de Office 2016, o si ya no la soporta Windows 10. Quizás me falte instalar algún paquete de Visual Basic o de Visual Studio.
Sin embargo, estas opciones no me valían como solución de última hora. Implicaban rehacer todo mi código para que presentara en todo momento un formulario en pantalla. Sin embargo, mi aplicación no estaba pensada así, y no iba a ponerme a rehacerlo todo y a introducir errores a esas alturas.
Situación
Mi macro abre un archivo, copia unos 800 registros en memoria, cierra ese archivo y luego va colocando cada valor en su sitio en el documento principal, en el que está la macro. Este archivo tiene unas 25 pestañas, y la macro va saltando de una a otra, insertando filas, eliminándolas, copiando valores, etc. Toda la macro está envuelta en un bucle que recorre los 800 registros, por lo que con bastante sencillez puedo saber en qué iteración del bucle me encuentro, simplemente consultando la variable del bucle. Mi código era algo así:
Application.ScreenUpdating = False
Hacemos muchas cosas para cargar los datos en memoria
for cont = 1 to max
Hacemos muchas cosas para colocar cada dato en su sitio
next cont
Application.ScreenUpdating = True
Todo funciona a partir de una pestaña de control que he generado como interfaz, que simplifica la interacción del usuario. En esa pestaña el usuario selecciona los archivos que hay que leer y hay un botón que es el que desata todos los males. Es algo así como:
Solución inicial
Al principio se me ocurrió escribir en una celda qué es lo que estamos haciendo en cada momento. Eso es muy sencillo. La pestaña inicial se llama INICIAL. Lo único que hay que hacer es activar la pestaña INICIAL, activar el ScreenUpdating, cambiar el valor de la celda, volver a desactivar el ScreenUpdating y volver a la pestaña en la que me andaba haciendo cosas.
Como seguramente sabrás, ScreenUpdating es una propiedad del objeto Application. Cuando su valor es True, entonces cada cambio que se haga se verá en pantalla. Si cambias de pestaña, eso hará la pantalla. Cuando ScreenUpdatin = False, entonces Excel hace todo sin representarlo en pantalla. De esta manera se realizan las operaciones siempre más rápido, y además no molestamos al usuario con parpadeos de pantalla que no le aportan nada útil a su vida.
Así que me puse manos a la obra, y básicamente el código quedó más o menos así:
Application.ScreenUpdating = False
Hacemos muchas cosas para cargar los datos en memoria
for cont = 1 to max
Sheets("INICIAL").Activate
Application.ScreenUpdating = True
Cells(21,5).Value = "Estamos haciendo cosas en la pestaña XXXX"
Application.ScreenUpdating = False
Sheets("XXXX").Activate
Hacemos muchas cosas para colocar cada dato en su sitio
next cont
Application.ScreenUpdating = True
De esta manera, me quedaba algo así:
Barra de progreso
Sin embargo, seguía sin gustarme. Quería algo más visual. Le das al botón, te levantas a hacer papeles a otra mesa, pero puedes echar un ojo de vez en cuando desde lejos para saber cómo vamos. Y se me ocurrió una idea muy sencilla:
¿Y si utilizo un gráfico de barras con una sola barra?
Y eso hice. Los pasos son los siguientes:
- Insertar un gráfico de barra agrupada.
- Con botón derecho sobre el gráfico, pinchar en “Seleccionar datos”.
- Pinchar en el botón “Agregar”.
- El nombre de la serie lo dejamos en blanco. En “Valores de la serie” seleccionamos la celda E23. Aceptar. Aceptar. (Puedes seleccionar la celda que más te interese. Yo he seleccionado una que va a quedar debajo de mi gráfica, para que no se vea)
- Seleccionamos el título del gráfico y lo eliminamos. Lo mismo con el 1 que aparece a la izquierda.
- Pinchamos una vez sobre cualquier número del eje horizontal y luego, con botón derecho sobre el mismo eje, pinchamos en “Dar formato al eje”.
- En “Opciones del eje” ponemos los siguientes valores: mínimo = 0, máximo = 100, unidad mayor = 25. (Aunque alguno de los valores ya marque lo mismo, lo escribimos de nuevo. Esto es porque por defecto, Excel recalcula automáticamente estos valores, pero nosotros queremos que sean siempre fijos.)
- Ajustamos el tamaño del gráfico a lo que nos interese
Y ya tenemos nuestra barra de progreso. Si quieres, puedes jugar con otros apartados del gráfico para que quede exactamente a tu gusto. Yo he cambiado un parámetro que se llama “Ancho del intervalo” para ajustar el ancho de la barra, y he eliminado la línea exterior del gráfico.
Al final, queda algo así:
En este caso la gráfica marca 50, porque es el valor que he puesto en la celda a la que hacíamos referencia, en mi caso la E23. Ya solo nos queda retocar el código para que nos informe del porcentaje de avance que llevamos. Para eso haremos lo siguiente (marco en color verde las novedades):
Application.ScreenUpdating = False
Hacemos muchas cosas para cargar los datos en memoria
for cont = 1 to max
Sheets("INICIAL").Activate
Application.ScreenUpdating = True
Cells(21,5).Value = "Estamos haciendo cosas en la pestaña XXXX"
Cells(23,5).Value = (cont/max)*100
Application.ScreenUpdating = False
Sheets("XXXX").Activate
Hacemos muchas cosas para colocar cada dato en su sitio
next cont
Application.ScreenUpdating = True
Y con esto ya tenemos una barra de progreso sencillísima de manejar, pues simplemente hay que cambiar el valor de una celda.
Enlaces de interés
Para saber cómo se trabaja con los gráficos en Excel puedes consultar nuestra Guía completa. También puedes consultar la documentación de Microsoft.
En esta página de Microsoft puedes encontrar más información sobre la propiedad ScreenUpdating. También hemos escrito sobre ello en ExcelyVBA aquí.