Optimizando Código Xojo: Timers mediante código y AddHandler

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.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *