Skip to content

Optimizing Xojo Code, Part 2: Using a Timer to Keep the UI Responsive

Welcome back! If you missed the first part in this series, check out Optimizing Xojo Code, Part 1: Getting Started, where we dissected the blocking While loop that counted up to kCountTo, updated a label, and kept the UI responsive only by calling App.DoEvents. That code works, but it spends most of its life running on the UI thread. In this tutorial we’ll rebuild that workflow step by step and end up with the first optimized solution: a timer-driven solution that keeps the interface responsive.

Step 1: Let’s sketch the goal

We will need a button that, when pressed, starts a simulated wait that updates a label every 100 ms until a fixed duration (kCountTo, which remains 20000 ms in our example) is reached. So, the timer will fire periodically and handle the counting there. The button simply resets state and starts the timer.

Step 2: Prepare the UI components

Create a DesktopLabel named StatusLabel to display progress.
Add a DesktopButton (caption it “Method 1”) whose Pressed event will kick off the timer.
Finally, place a Timer control onto the window, name it mTimer, set its Period to 100, and set RunMode to Multiple (but leave it off until the button starts it).
Add an Integer property to the window such as mMsWaited to accumulate elapsed milliseconds, and keep kCountTo defined as 20000.

Step 3: Wire up the button

The button handler becomes very simple. Reset the tracked milliseconds, show "0" in the label, ensure the timer runs at 100 ms ticks, and let it fire repeatedly:

Sub Pressed()
  // Reset the tracked elapsed ms and start the timer at 100 ms ticks.
  mMsWaited = 0
  StatusLabel.Text = "0"
  mTimer.Period = 100
  mTimer.RunMode = Timer.RunModes.Multiple
End Sub

This code primes the state but does not block. The timer will perform the actual counting.

Step 4: Let the timer take over

Implement mTimer.Action to run on the UI thread. Each tick adds the timer’s period to mMsWaited, updates the label, and turns itself off once kCountTo has been reached:

Sub Action()
  mMsWaited = mMsWaited + Me.Period

  If mMsWaited >= kCountTo Then
    Me.RunMode = Timer.RunModes.Off
    StatusLabel.Text = "done"
  Else
    StatusLabel.Text = mMsWaited.ToString
  End If
End Sub

This keeps your UI responsive because the timer fires briefly and returns control back to the event loop instead of spinning inside a While loop.

Step 5: Test the flow

Run the app, click the button previously created and watch the label count up and stop at the target value. The timer approach lets other interface interactions remain responsive while still providing clear progress feedback.

What makes this timer driven solution a solid first step?

It shows how you can preserve the original behavior while giving the UI breathing room. It avoids App.DoEvents, reduces tight loops, and still delivers frequent updates. In the next article we’ll build on this idea and explore alternative approaches that continue to improve responsiveness and structure.

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: