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:
- Optimizing Xojo Code, Part 1: Getting Started
- Optimizing Xojo Code, Part 2: Using a Timer to Keep the UI Responsive
