Skip to content

Optimizing Xojo Code, Part 4: Timer.CallLater

In Part 1 of this series, we looked at a common 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 Window. In Part 3, we advanced to creating Timers programmatically with AddHandler for use in classes and modules.

Now, for even simpler one-off or chained delayed tasks, Xojo offers Timer.CallLater: no Timer instance required.

The Strategy: Timer.CallLater

Timer.CallLater(milliseconds, AddressOf MethodName, arg As Variant) schedules your method to run after the specified delay on the main UI thread. Pass data via the Variant parameter. To chain calls (like our countdown), re-call it from within the method. Use Timer.CancelCallLater(AddressOf MethodName) to abort pending calls.

For full details, see the Timer documentation.

Looking at the Code

Prerequisites: Add a StatusLabel (DesktopLabel control) and a constant kCountTo As Integer = 20000.

Let’s look at how we implement this.

The Setup (Button Pressed)

Place the following code in the Pressed event handler of a button control:

Sub Pressed()
  Timer.CancelCallLater(AddressOf UpdateProgress)
  
  StatusLabel.Text = "0"
  
  Timer.CallLater(100, AddressOf UpdateProgress, 100)
End Sub

The Handler (Recursive Chain)

Create the following method that handles the recursive chain of delayed updates:

Sub UpdateProgress(elapsedMs As Variant)
  Var elapsed As Integer = elapsedMs.IntegerValue
  
  If elapsed >= kCountTo Then

    StatusLabel.Text = "done"

  Else

    StatusLabel.Text = elapsed.ToString
    Timer.CallLater(100, AddressOf UpdateProgress, elapsed + 100)

  End If
End Sub

Crucial Note: The handler method must accept a Variant parameter to receive the argument passed to CallLater. Always use type-safe extraction like .IntegerValue.

How It Works

  1. Initial Schedule: The button cancels any pending calls and schedules the first UpdateProgress after 100ms, passing 100 as the elapsed time (just in case we like pressing a button multiple times quickly).
  2. Recursion: Each call updates the UI and, if not finished, schedules the next one 100ms in the future with incremented elapsed time.
  3. Automatic Management: No Timer properties or handlers to manage; Xojo handles scheduling and cleanup.
  4. Cancellation: Ensures only one chain runs at a time.

Wrapping Up

Timer.CallLater shines for delayed UI updates or chained tasks without the overhead of Timer objects. It’s concise, safe, and powerful for responsive apps.

In Part 5, we’ll tackle true background processing with Threads and UserInterfaceUpdate.

Until then, happy coding!

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: