🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA DoEvents en Excel — evita que Excel se quede en «No responde» (y por qué deja que tu macro corra dos veces)

|

VBA DoEvents en Excel — evita que Excel se quede en «No responde» (y por qué deja que tu macro corra dos veces)

TL;DRDoEvents pausa 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 a DoEvents en 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 DoEvents en 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 frecuenciaDoEvents en 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é DoEvents no 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