Skip to content

Optimizing Xojo Code, Part 3: Programmatic Timers and AddHandler

In Part 1 of this Optimizing Xojo Code series, we looked at a working but discouraged approach using a tight loop with DoEvents to keep the UI from freezing. In Part 2, we explored a better alternative by replacing that loop with a Timer control dragged onto a DesktopWindow. This is a simple and effective solution that takes advantage of Xojo’s object-oriented nature.

But what if you need a timer inside a Class or a Module where you can’t drop a visual control?

The Strategy: AddHandler

When you use a Timer control from the library, you double-click it to add an Action event. When we create a Timer in code, we don’t have a “code editor” for it in the same way. Instead, we use the AddHandler command to tell Xojo: “When this timer fires its Action event, run this specific method instead.”

Looking at the Code

Let’s look at how we implement this. In our example project, we have a button that initializes our timer and a separate method to handle the “ticks.”

The Setup

First, we define a property on our window (or class) to hold our timer: mWaitTimer As Timer

Then, in the Pressed event of our button, we instantiate it:

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

The Handler (Doing the Work)

Now, let’s create the method named WaitTickCrucial Note: When using AddHandler for a Timer, the first parameter of your receiving method must be of the type Timer so it knows which object triggered it.

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

How It Works

  1. New Timer: We create a new instance of the Timer class in memory.
  2. AddHandler: This command connects the Action event of our new timer to the WaitTick method. The AddressOf operator tells Xojo the memory location of the code we want to run.
  3. Passing the Object: Because WaitTick receives t As Timer as a parameter, you can actually use the same handler for multiple different timers and knows exactly which one is calling for attention.

Wrapping Up

By moving your Timers into code, you take a significant step toward writing more modular Xojo applications. You’ve moved the logic from “Global UI state” into “Managed Code execution.”

In the upcoming Part 4, we’ll look at a shortcut that makes one-off background tasks a breeze: Timer.CallLater.

Until then, happy coding and don’t forget to add your own solution in the Xojo Forum!

Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!

Optimizing Code Series: