Excel VBA: Formulario de usuario funcionando mal después de 6 segundos
Resuelto
Patrice33740
Mensajes publicados
8400
Fecha de registro
Estado
Miembro
Última intervención
-
EGM -
EGM -
Hola,
Utilizo un formulario no modal (fStatus) con un título (lblStatus) para mostrar el progreso de la exploración por macros de un gran libro de Excel (170 hojas de aproximadamente 50 filas y 30 columnas).
Alrededor de 6 segundos después de iniciar la macro, el formulario deja de actualizarse (en pantalla) aunque la macro continúa normalmente. En ese momento, el cursor de reloj de arena es reemplazado por el cursor normal y, a veces, el formulario se borra y su ubicación queda en blanco.
He añadido un BlockInput para evitar cualquier interacción del usuario durante la ejecución de la macro (antes, un clic derecho provocaba el mismo fenómeno).
Aquí está el código (muy simplificado):
Option Explicit
Option Private Module
Declare Function BlockInput Lib "user32" (ByVal fBlockIt As Long) As Long
Public Sub Test()
Dim frmStatus As fStatus
Dim wsh As Excel.Worksheet
Dim wbkCible As Excel.Workbook
Dim cell As Excel.Range
Dim ctr As Long
Application.Calculation = xlCalculationManual
Application.Cursor = xlWait
Application.ScreenUpdating = False
Set wbkCible = Application.ActiveWorkbook
Set frmStatus = New fStatus
frmStatus.Show
BlockInput 1
For Each wsh In wbkCible.Worksheets
wsh.Select
frmStatus.lblStatus.Caption = wsh.Name
frmStatus.Repaint
For Each cell In wsh.UsedRange
cell.Select
For ctr = 1 To 2000: Next
Next cell
Next wsh
Application.ScreenUpdating = True
Application.Cursor = xlDefault
Application.Calculation = xlCalculationAutomatic
frmStatus.Hide
Unload frmStatus
Set frmStatus = Nothing
BlockInput 0
End Sub
Diferentes valores de la bucle For
For ctr = 1 To 2000: Next
me han permitido verificar que el problema sigue ocurriendo tras aproximadamente 6 segundos.
¿Alguien tiene alguna idea de qué está pasando?
Configuración: XP / Mozilla / Office 2003
--
Nicolas dice siempre: «¡Es fácil cuando se conoce la respuesta!»
Utilizo un formulario no modal (fStatus) con un título (lblStatus) para mostrar el progreso de la exploración por macros de un gran libro de Excel (170 hojas de aproximadamente 50 filas y 30 columnas).
Alrededor de 6 segundos después de iniciar la macro, el formulario deja de actualizarse (en pantalla) aunque la macro continúa normalmente. En ese momento, el cursor de reloj de arena es reemplazado por el cursor normal y, a veces, el formulario se borra y su ubicación queda en blanco.
He añadido un BlockInput para evitar cualquier interacción del usuario durante la ejecución de la macro (antes, un clic derecho provocaba el mismo fenómeno).
Aquí está el código (muy simplificado):
Option Explicit
Option Private Module
Declare Function BlockInput Lib "user32" (ByVal fBlockIt As Long) As Long
Public Sub Test()
Dim frmStatus As fStatus
Dim wsh As Excel.Worksheet
Dim wbkCible As Excel.Workbook
Dim cell As Excel.Range
Dim ctr As Long
Application.Calculation = xlCalculationManual
Application.Cursor = xlWait
Application.ScreenUpdating = False
Set wbkCible = Application.ActiveWorkbook
Set frmStatus = New fStatus
frmStatus.Show
BlockInput 1
For Each wsh In wbkCible.Worksheets
wsh.Select
frmStatus.lblStatus.Caption = wsh.Name
frmStatus.Repaint
For Each cell In wsh.UsedRange
cell.Select
For ctr = 1 To 2000: Next
Next cell
Next wsh
Application.ScreenUpdating = True
Application.Cursor = xlDefault
Application.Calculation = xlCalculationAutomatic
frmStatus.Hide
Unload frmStatus
Set frmStatus = Nothing
BlockInput 0
End Sub
Diferentes valores de la bucle For
For ctr = 1 To 2000: Next
me han permitido verificar que el problema sigue ocurriendo tras aproximadamente 6 segundos.
¿Alguien tiene alguna idea de qué está pasando?
Configuración: XP / Mozilla / Office 2003
--
Nicolas dice siempre: «¡Es fácil cuando se conoce la respuesta!»
10 respuestas
-
Hola al foro
Quizás haya una solución con DoEvents.
DoEvents cede el control al sistema operativo hasta que este haya terminado de procesar los eventos de su cola
Mytå
--
Versiones instaladas [MsProject 2003(FR), Excel 2003-2007(FR)] -
Gracias a todos,
la solución de Mytå funciona bien, he colocado DoEvents en el bucle justo antes de modificar el control:
For Each wsh In wbkCible.Worksheets DoEvents frmStatus.lblStatus.Caption = wsh.Name frmStatus.Repaint ....
La macro recupera su velocidad normal.
Pongo el puesto como resuelto
Patrice
--
Nicolas dice siempre: « ¡Es fácil cuando se conoce la respuesta! » -
hola
Me parece un fenómeno bastante conocido para una visualización en un bucle largo.
Cuando modifiques tu título (lblStatus), intenta añadir :lblStatus.Repaint
Esto fuerza la visualización que debería funcionar mejor.
--
Siempre zen -
Hola gbinforme
la actualización de la visualización del formulario ya está presente en el código: frmStatus.Repaint
cuando intento aplicarlo al título (frmStatus.lblStatus.Repaint) obtengo un error de compilación « Miembro de método o datos no encontrado » ya que el método no se aplica a los UILabel (etiquetas).
--
Nicolas dice siempre: « ¡Es fácil cuando ya se sabe la respuesta! » -
hola
Utiliza mejor una textbox para mostrarlo porque efectivamente un título no está hecho para eso.
Es efectivamente en el userform donde hay que aplicar la función y si no quieres que ralentice demasiado el proceso, no debes modificar el contenido hasta pasadas varias segundos (20-30) porque la visualización tarda mucho en comparación con los cálculos.
--
Siempre zen -
Hola gbinforme, gracias por tu respuesta.
He intentado reemplazar el Label por un TextBox pero eso no cambia nada!
Por otro lado he explorado la posibilidad de colocar varios .Repaint en el bucle aunque el contenido del UserForm no cambie.
Colocando un .Repaint en el bucle Cell, funciona pero, por supuesto, ¡la duración de la macro se vuelve excesivamente larga!
En compromiso, intenté usar la función Timer para hacer un refresco cada segundo pero eso no funciona, la frecuencia no es suficiente.
He colocado un contador en el bucle Cell y he hecho varios ensayos con una frecuencia de refresco cada vez mayor: no es satisfactorio.
Curiosamente, he encontrado un compromiso aceptable realizando un .Repaint al inicio de cada fila (mientras que con el método anterior hacía falta varios por fila) :
For Each cell In wsh.UsedRange
If cell.Column = 1 Then frmStatus.Repaint
...
Next
Esto no resuelve el problema, sino que simplemente evita que ocurra.
Ya había observado un fenómeno similar con Application.StatusBar
al explorar archivos grandes: después de cierto tiempo, la visualización se congela, ya no se actualiza con cada cambio mientras que la macro continúa funcionando.
Creo que un proceso ajeno a Excel toma el control y no lo restituye adecuadamente.
Probablemente haya una solución usando la API de Windows, pero no he encontrado nada al respecto.
Patrice -
Hola,
Por cierto, he utilizado el siguiente código para mostrar un mensaje de paciencia (nombre del UserForm) en un procedimiento bastante largo para enviar correos y funciona bien.
El código:
Application.Cursor = xlWait 'muestra la hora de arena Patience.Show vbModeless 'muestra el UserForm pero continúa el procesamiento Patience.Repaint 'refresca el contenido mostrado; de lo contrario aparece una caja blanca vacía ` **** ` Aquí mi procedimiento de procesamiento [ClientAdresseCourriel clofpro, clsage, nbli, clbcmde, connecte] `**** Workbooks(clsage).Close ` cierra el libro de direcciones a procesar Unload Patience ' cerrar el UserForm Application.Cursor = xlDefault 'restablece el cursor por defecto
--
Saludos.
Le Pingou-
Bonjour Le Pingou,
Je suppose que dans ta procédure tu modifies le contenu de "patience" et que tu vois le résultat ?
J'ai créé à peu près le même procédé pour générer une application internet HTML qui comporte de nombreuses pages (que je liste au fur et à mesure) à partir d'une base de données et cela fonctionne comme prévu.
Aussi je suis surpris que Patrice rencontre ce problème avec le repaint qui se met en grève. -
-
-
Hola Le Pingou et gbinforme,
Gracias por interesarse en mi problema.
Declaré mi UserForm no modal en VBE poniendo directamente ShowModal en False, pero vi al usar el Explorador de objetos que ShowModal no aparece en las propiedades del UserForm (es la única que falta), por lo que se instauró la duda y seguí el consejo de Le Pingou:
intenté frmStatus.Show vbModeless para estar más seguro, pero el problema persiste.
Algunas precisiones:
- en la bucle que crea el problema, la frecuencia de actualización es ligeramente superior a un segundo (paro a la 6ª o 7ª hoja).
- uso este mismo UserForm en otros procedimientos del módulo y funciona muy bien, pero la frecuencia de actualización es más alta (0,5 a 0,7 segundos).
- en la bucle, cuando añado un Repaint en cada línea explorada (sin cambio del userform) el userform funciona correctamente pero el tiempo de ejecución ...
- estoy convencido de que el tamaño del archivo explorado influye en el comportamiento de la visualización de la aplicación, pero es solo una convicción.
- el archivo explorado no es realmente enorme: 9 MB que contienen principalmente datos, fórmulas y algunos gráficos de Excel (menos de una quincena), sin objetos externos, sin imágenes, miles de hipervínculos pero todos destinados a celdas internas en el archivo.
Cordialement
Patrice
-- Nicolas dice siempre: « ¡Es fácil cuando se sabe la respuesta! »-
hola a todos,
La duración entre dos repaint no tiene mucha importancia a mi parecer, pero me parece que solo es útil usarla cuando el valor a mostrar cambia.
Me parece que la duración "útil" sería más bien superior a 10-15 segundos, porque por debajo de eso ralentiza la macro y la reacción del usuario no es del orden de un segundo: solo Usain Bolt recorre más de 10 m en ese tiempo.
El tamaño del archivo no es el único factor, ya que importa sobre todo en función de la memoria disponible: si falla y hay que recurrir al swap, el tiempo se eleva.
¿Has inhibido el refresco de pantalla?
Intenta hacer un repaint cada 10 líneas para ver.
-
-
Hola gbinforme,
he intentado refrescar cada 10, 5, 2 líneas pero no es suficiente, solo funciona con 1 línea (o menos), además los Repaint en cada línea se realizan aunque el valor no cambia (cambia solo en cada hoja).
Al inicio del código tengo un
Application.ScreenUpdating = False
La cantidad de memoria es más que suficiente para evitar el swap.
--
Nicolas siempre dice: « ¡Es fácil cuando ya se la respuesta! » -
Buenas de nuevo
Si no pongo este Repaint, sin interés teórico, el UserForm se queda sin ideas a los 6 segundos!
Ahí es donde está mi problema.
Atentamente
Patrice
--
Nicolás siempre dice: «¡Es fácil cuando ya se conoce la respuesta!»