A continuación encontrarás traducido al castellano el artículo escrito por Gabriel Ludosanu y publicado originalmente en el Blog oficial de Xojo.
En la primera parte de esta serie de artículos vimos una técnica común, pero poco aconsejable, sobre cómo utilizar un bucle en combinación con DoEvents para mantener la interfaz de usuario con capacidad de respuesta ante las acciones del usuario. En la segunda parte exploramos una alternativa mejor, sustituyendo dicho bucle con un control Timer añadido en la ventana del proyecto desde la Librería. En la Parte 3 hemos avanzado viendo como crear dichos Timer en tiempo de ejecución, y en combinación con AddHandler, para su uso tanto en clases como en Módulos.
Ahora mostramos un enfoque incluso más simple para aquellas acciones que deban realizarse una sola vez o bien de forma encadenada y con algo de demora. Para ello Xojo ofrece Timer.CallLater, donde no se precisa crear una instancia de Timer.
La Estrategia: Timer.CallLater
Timer.CallLater(milliseconds, AddressOf MethodName, arg As Variant) programa el método pasado mediante AddressOf para que se ejecute en el hilo principal de la app (que es sobre el que se ejecutan también los elementos de la interfaz de usuario) una vez que hayan transcurrido los milisegundos indicados. Se pasan los datos mediante el parámetro de tipo Variant. Para encadenar llamadas (como en nuestra cuenta atrás), lo volvemos a llamar desde el propio método. Utiliza Timer.CancelCallLater(AddressOf MethodName) para abortar o cancelar las llamadas pendientes.
Para obtener más detalles sobre su funcionamiento, consulta la Documentación de Xojo.
El Código
Pre-requisitos: Añade una etiqueta StatusLabel (control DesktopLabel) y una constante kCountTo As Integer = 20000.
Veamos como implementarlo.
La Configuración (Button Pressed)
Incluye el siguiente código en el evento Pressed correspondiente a un control de tipo Botón:
Sub Pressed() Timer.CancelCallLater(AddressOf UpdateProgress) StatusLabel.Text = "0" Timer.CallLater(100, AddressOf UpdateProgress, 100) End Sub
El Manejador (cadena recursiva)
Crea el siguiente método encargado de gestionar la cadena recursiva con las actualizaciones de ejecución demorada:
Sub UpdateProgress(elapsedMs As Variant)
Var elapsed As Integer = elapsedMs.IntegerValue
If elapsed >= kCountTo Then
StatusLabel.Text = "done"
Else
StatusLabel.Text = elapsed.ToString
Timer.CallLater(100, AddressOf UpdateProgress, elapsed + 100)
End If
End Sub
Nota: el método debe de aceptar un parámetro de tipo Variant para recibir el argumento pasado mediante CallLater. Utiliza siempre una extracción del valor de tipo seguro; como por ejemplo .IntegerValue.
Como funciona
- Ejecución Inicial: El botón cancela cualquier llamada pendiente y añade el primer UpdateProgress tras 100 milisegundos, pasando 100 como el tiempo de demora.
- Recursión: cada llamada actualiza la IU y, si no ha finalizado, añade la siguiente llamada dentro de 100 milisegundos en el futuro con el tiempo de demora incrementado.
- Gestión automática: no es preciso trabajar con propiedades o manejadores de Timer. Xojo se encarga de realizar la gestión de las llamadas y el limpiado posterior.
- Cancelación: garantiza que sólo se ejecute una cadena cada vez.
En conclusión
Timer.CallLater brilla cuando se trata de realizar actualizaciones de la IU o bien encadenar tareas sin todo el sobrecoste que conlleva instanciar o trabajar con objetos Timer. Es conciso, seguro y potente para garantizar que las apps se mantengan con respuesta frente a las acciones del usuario de la app.
En la siguiente entrega veremos como trabajar con procesos en segundo plano mediante Threads (hilos) y UserInterfaceUpdate.
Hasta entonces… ¡feliz programación con Xojo!