TL;DR —
DoEventspausa tu macro por una fracción de segundo y deja que Excel maneje los clics, las pulsaciones de teclas y los repintados que se pusieron en cola mientras tu código estaba ocupado. Eso es lo que evita que la ventana se ponga gris en «No responde», y es lo que hace posible un botón de cancelar que funcione. Pero la misma cesión le devuelve el control al usuario a mitad de macro — así que puede pulsar tu botón otra vez y lanzar una segunda copia de la macro dentro de la primera. Protege esa reentrada con un flag de ejecución, y llama aDoEventsen un intervalo, no en cada iteración:
Private mRunning As Boolean
Sub LongJob()
If mRunning Then Exit Sub ' guarda de reentrada - rechaza arrancar una segunda copia
mRunning = True
On Error GoTo CleanExit
Dim i As Long
For i = 1 To 500000
' ... trabaja sobre la fila i ...
If i Mod 1000 = 0 Then DoEvents ' cede de vez en cuando para que Excel siga vivo
Next i
CleanExit:
mRunning = False ' limpia siempre el flag, incluso tras un error
End Sub
Un bucle largo de VBA corre en el único hilo de Excel, y mientras corre Excel no puede hacer nada más —
ni repintar, ni registrar un clic, ni actualizar la barra de título. Tras unos segundos Windows decide
que la aplicación está colgada y le estampa «No responde» encima, aunque tu macro esté funcionando
perfectamente. DoEvents es la válvula de escape. Esta guía se construye sobre una sola idea —
DoEvents compra capacidad de respuesta cediendo el control, y «ceder el control» incluye darle al
usuario el control para romper cosas. No es una línea gratis de «haz que Excel vaya fluido»; es un
trato, y tienes que pagar la parte de la reentrada.
Lo que aprenderás
- El modelo mental — un hilo, una cola de mensajes, y por qué un bucle congela la ventana
- Qué hace
DoEventsen realidad — vaciar la cola, luego reanudar - El verdadero peligro — la reentrada, y la guarda del flag de ejecución que la detiene
- Por qué debes moderar su frecuencia —
DoEventsen cada iteración puede dominar tu tiempo de ejecución - Cómo impulsa un botón de cancelar, y cómo eso conecta con una barra de estado
- Por qué
DoEventsno es multihilo, y cuándo simplemente dejarlo fuera
El modelo mental: un hilo y una cola que nunca se lee
Excel corre tu VBA en el mismo hilo único que usa para todo lo demás — dibujar la cuadrícula, manejar tu ratón, refrescar la cinta. Mientras una macro está en marcha, ese hilo es 100% tuyo. Cada clic y pulsación de tecla que hace el usuario no desaparece; aterriza en una cola de mensajes y espera. Pero nada está leyendo la cola, porque el hilo está ocupado en tu bucle. La pantalla se queda obsoleta, la cola se acumula, y tras unos segundos Windows pinta «No responde» sobre la ventana.
DoEvents lee la cola. Cuando lo llamas, VBA pausa tu macro, deja que Excel procese todo lo que
espera — repintar la pantalla, manejar los clics, ejecutar cualquier manejador de eventos disparado —
y luego devuelve el control a la línea siguiente a DoEvents para que tu macro continúe.
' ... tu bucle esta acaparando el hilo; la ventana esta congelada ...
DoEvents ' Excel vacia la cola: repinta, procesa clics, ejecuta manejadores, luego vuelve
' ... tu macro se reanuda aqui ...
Eso es genuinamente útil: la ventana se mantiene receptiva, la barra de estado que pusiste de verdad se repinta, y el usuario puede interactuar. El problema es exactamente esa última parte.
El verdadero peligro: la reentrada
Aquí está el fallo que hace a DoEvents peligroso en vez de simplemente lento. Tu macro la lanza un
botón. A mitad de camino, llamas a DoEvents. Excel procesa la entrada en cola — y el usuario, viendo
que la macro «tarda un rato», ha pulsado el mismo botón otra vez. Ese clic se maneja ahora durante
tu DoEvents, así que Excel arranca una segunda ejecución de la macro mientras la primera sigue en
pausa dentro del bucle. Dos copias ahora se entrelazan sobre los mismos datos.
Los resultados van de lo incorrecto a lo catastrófico: filas procesadas dos veces, un contador que
cuenta doble, un archivo escrito por las dos ejecuciones, o un error de plano cuando la segunda
ejecución modifica un estado que la primera daba por estable. Esto es reentrada, y es el bug número
uno de DoEvents — la misma familia de fallos que un manejador de eventos que se dispara a sí
mismo.
La guarda es un flag a nivel de módulo que rechaza una segunda entrada:
Private mRunning As Boolean
Sub LongJob()
If mRunning Then Exit Sub ' ya esta corriendo - ignora el clic extra
mRunning = True
On Error GoTo CleanExit
' ... bucle con DoEvents ...
CleanExit:
mRunning = False ' limpia en exito Y en error, o te bloqueas a ti mismo
End Sub
Fíjate en que el restaurado CleanExit tampoco es opcional aquí: si un error se salta mRunning = False, el flag se queda en True y la macro se niega a volver a correr hasta que reinicias el
proyecto. La misma disciplina de On Error que cada interruptor de este clúster.
Modera su frecuencia: DoEvents no es gratis
Incluso sin reentrada, DoEvents tiene un coste. Vaciar la cola de mensajes y ceder al sistema
operativo lleva tiempo real — a menudo mucho más que la diminuta pieza de trabajo de una iteración del
bucle. Llámalo en cada iteración de un bucle apretado y puedes convertir una macro de 2 segundos en
una de 30, habiendo gastado la mayor parte del tiempo cediendo en vez de trabajando.
Así que llámalo en un intervalo — cada 1.000 filas, o cada cuarto de segundo con un temporizador — no en cada pasada:
For i = 1 To n
' ... trabajo ...
If i Mod 1000 = 0 Then DoEvents ' bastante receptivo, sin pagar en cada fila
Next i
El intervalo es un dial: más frecuente significa una ventana más ágil y un botón de cancelar más
receptivo; menos frecuente significa un rendimiento bruto más rápido. i Mod 1000 es un buen punto de
partida para trabajo rápido por fila; ajústalo a lo que tarde cada iteración.
El botón de cancelar que hace posible
La ventaja que te enseña la reentrada es también la función que la gente más quiere: como DoEvents
deja que Excel procese los clics a mitad de ejecución, un usuario puede pulsar un botón de Cancelar y
hacer que se registre mientras la macro sigue en el bucle. Conecta un flag público al botón y
compruébalo después de cada DoEvents:
Public gCancel As Boolean ' lo pone en True el manejador de clic de un boton Cancelar
Sub LongJob()
Dim i As Long
For i = 1 To 500000
' ... trabajo ...
If i Mod 1000 = 0 Then
DoEvents
If gCancel Then Exit For ' el clic paso - detente limpiamente
End If
Next i
End Sub
Sin DoEvents, el clic de Cancelar simplemente se queda en la cola hasta que la macro termina por su
cuenta — inútil. Con él, el botón funciona. Empáralo con un mensaje de barra de
estado para que el usuario pueda ver el progreso y detenerlo.
Por qué no es multihilo — y cuándo saltártelo
DoEvents no corre tu macro en segundo plano ni en otro hilo. Todo sigue siendo en serie en el
único hilo; DoEvents solo entrelaza el trabajo pendiente de Excel entre trozos del tuyo. Tu bucle no
se acelera — si acaso se ralentiza — solo deja de bloquear la interfaz. Si de verdad necesitas que el
trabajo corra en paralelo, esa es una herramienta completamente distinta (un proceso aparte, o un
lenguaje con hilos), no DoEvents.
Y el criterio honesto por defecto: si una macro termina en menos de un segundo o dos, nunca dispara «No
responde», así que DoEvents añade coste y riesgo de reentrada sin ningún beneficio — déjalo fuera.
Échale mano solo cuando la ejecución sea lo bastante larga como para que una ventana congelada sea un
problema real, y una vez lo hagas, protege la reentrada y modera las llamadas. Una macro rápida con
DoEvents salpicado por su bucle es más lenta y más frágil que la misma macro sin él.
Cómo ayuda ExcelMaster
Usar bien DoEvents es un paquete de decisiones de criterio: solo en ejecuciones largas, en un
intervalo y no en cada iteración, tras una guarda de reentrada, con el flag limpiado en un manejador de
errores, y emparejado con una comprobación de cancelación y un mensaje de progreso. Falla cualquiera de
ellas y te llevas una macro que corre dos veces, o una que se arrastra, o un botón de Cancelar que nunca
se dispara.
ExcelMaster toma esas decisiones
por ti. Pídele «una importación larga que se mantenga receptiva y se pueda cancelar» y añade un flag de
ejecución para bloquear la reentrada, llama a DoEvents en un intervalo sensato, comprueba un flag de
cancelación justo después, y limpia todo en un manejador CleanExit — así te llevas una macro receptiva
e interrumpible en vez de una ventana congelada o una doble ejecución.
Preguntas frecuentes
¿Qué hace DoEvents en Excel VBA?
DoEvents pausa tu macro brevemente y deja que Excel procese el trabajo de entrada y de repintado que se
puso en cola mientras corría tu código — clics, pulsaciones de teclas, redibujados de pantalla, y
cualquier manejador de eventos disparado. Luego devuelve el control a la línea siguiente y tu macro
continúa. Es lo que evita que una macro larga congele la ventana de Excel en «No responde».
¿Por qué Excel dice «No responde» mientras corre mi macro?
Porque tu macro está usando el hilo único de Excel, así que Excel no puede repintar ni manejar la
entrada hasta que la macro cede. Tras unos segundos Windows marca la aplicación como colgada — aunque la
macro esté funcionando bien. Añadir DoEvents en un intervalo dentro de tu bucle deja que Excel respire,
y la etiqueta «No responde» desaparece.
¿Es peligroso DoEvents?
Puede serlo, por la reentrada. Como DoEvents deja que Excel procese los clics a mitad de ejecución, un
usuario puede relanzar la misma macro (pulsando su botón otra vez) mientras la primera ejecución está en
pausa, así que dos copias corren a la vez y corrompen el trabajo de la otra. Protégete con un flag de
«ejecución» a nivel de módulo que haga que la macro salga si ya está corriendo, y limpia el flag en un
manejador de errores.
¿Debo llamar a DoEvents en cada iteración del bucle?
No — modera su frecuencia. DoEvents tiene una sobrecarga real, y llamarlo en cada iteración de un bucle
apretado puede dominar tu tiempo de ejecución y hacer la macro mucho más lenta. Llámalo en un intervalo
en su lugar, como If i Mod 1000 = 0 Then DoEvents, y ajusta el intervalo a lo que tarde cada
iteración.
¿DoEvents hace mi macro multihilo o más rápida?
No. Todo sigue corriendo en serie en un hilo; DoEvents solo entrelaza el trabajo de interfaz pendiente
de Excel entre trozos de tu código. Tu bucle no se acelera — normalmente se ralentiza un poco — solo
deja de bloquear la interfaz. Para trabajo en paralelo de verdad necesitas un proceso aparte, no
DoEvents.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 18/08/2026.
Guías relacionadas: VBA StatusBar · VBA DisplayAlerts · VBA ScreenUpdating · VBA EnableEvents · VBA On Error
