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 sobre Optimización de Código Xojo vimos un enfoque funcional pero no recomendable sobre cómo usar DoEvents en un bucle para mantener la IU responsiva. En la segunda parte exploramos una alternativa mejor, sustituyendo dicho bucle con un control Timer arrastrado desde la Librería sobre una DesktopWindow. Esta es una solución simple y eficaz que saca provecho de la naturaleza orientada a objetos de Xojo.
Pero, ¿y si necesitas utilizar un Timer en una Clase o un Módulo sobre los cuales no puedes soltar un control visual?
La estrategia: AddHandler
Cuando utilizas un control Timer de la Librería, haces doble clic sobre él para añadirle el evento Action. Cuando creamos un Timer en código, no disponemos de un “editor de código” asociado con el mismo. En vez de ello utilizamos el comando AddHandler para indicarle a Xojo: “Cuando este Timer dispare su evento Action, has de ejecutar este método en vez de ello”.
Echando un vistazo al código
Echemos un vistazo al modo en el que implementamos esto. En nuestro proyecto de ejemplo, tenemos un botón que inicializa nuestro Timer en un método aparte para gestionar los “ticks”.
La configuración
En primer lugar, definiremos una propiedad en nuestra ventana (o clase) para que mantenga una referencia a nuestro Timer: mWaitTimer As Timer.
Luego, en el evento Pressed de nuestro botón crearemos una nueva instancia del Timer y la asignaremos sobre dicha propiedad:
Sub Pressed() Handles Pressed
' 1. Cleanup
If mWaitTimer <> Nil Then
mWaitTimer.RunMode = Timer.RunModes.Off
mWaitTimer = Nil
End If
' 2. Initialization
mElapsedMs = 0
StatusLabel.Text = "0"
' 3. Create the dynamic timer
mWaitTimer = New Timer
mWaitTimer.Period = 100 ' 100 ms tick
mWaitTimer.RunMode = Timer.RunModes.Multiple
' 4. The Magic: Link the Action event to our WaitTick method
AddHandler mWaitTimer.Action, AddressOf WaitTick
End Sub
El Handler (encargado del trabajo)
Crearemos ahora un método con el nombre WaitTick. Un apunte necesario: cuando se utiliza AddHandler para un Timer el primer parámetro del método ha de ser del tipo Timer, de modo que sepa sobre qué objeto se está actuando.
Sub WaitTick(t As Timer)
mElapsedMs = mElapsedMs + t.Period
If mElapsedMs >= kCountTo Then
' Achievement unlocked! Stop the timer and clean up
t.RunMode = Timer.RunModes.Off
StatusLabel.Text = "done"
' It's good practice to remove the handler when done
RemoveHandler t.Action, AddressOf WaitTick
Else
StatusLabel.Text = mElapsedMs.ToString
End If
End Sub
¿Cómo funciona?
- New Timer: creamos una nueva instancia de la clase Timer en memoria.
- AddHandler: este comando conecta el evento Action con nuestro nuevo método WaitTick. El operador AddressOf obtiene la dirección en memoria (punto de entrada) correspondiente al método en cuestión.
- Recibiendo el Objeto: dado que WaitTick recibe el parámetro t As Timer, puedes utilizar de hecho el mismo handler para varias instancias de Timer distintas, y saber exáctamente sobre cuál se ha de actuar.
En Resumen
Al mover tus Timer a código habrás dado un buen paso hacia delante en la escritura de aplicaciones Xojo más modulares. Has movido toda la lógica desde el “estado global de la IU” hacia una “ejecución gestionada por el código”.
En la próxima entrega veremos un atajo mediante el cual puedes ejecutar una tarea no repetitiva en segundo plano de forma realmente simple: Timer.CallLater.
Hasta entonces, ¡feliz programación! Y no te olvides de añadir tus propias soluciones en el Foro de Xojo.