ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Delphi Event-Driven UI Update Mechanism

Delphi / Object Pascal

Goal -- WPM

Ready
Exercise Algorithm Area
1type
2TUIUpdateEvent = class
3procedure ExecuteOnUIThread;
4end;
5
6TUIUpdateDispatcher = class
7private
8FUpdateQueue: TQueue<TUIUpdateEvent>;
9FLock: TCriticalSection;
10FMainThreadID: TThreadID;
11procedure ProcessUpdateQueue;
12public
13constructor Create;
14destructor Destroy;
15procedure PostUpdate(AUpdateEvent: TUIUpdateEvent);
16procedure CheckAndProcessUpdates;
17end;
18
19constructor TUIUpdateDispatcher.Create;
20begin
21inherited Create;
22FUpdateQueue := TQueue<TUIUpdateEvent>.Create;
23FLock := TCriticalSection.Create;
24FMainThreadID := GetCurrentThreadID;
25end;
26
27destructor TUIUpdateDispatcher.Destroy;
28var
29UpdateEvent: TUIUpdateEvent;
30begin
31// Ensure all pending updates are processed or discarded
32// In a real app, you might want to wait for processing or log errors
33while not FUpdateQueue.IsEmpty do
34begin
35UpdateEvent := FUpdateQueue.Dequeue;
36// Decide whether to free or attempt execution if possible
37UpdateEvent.Free;
38end;
39FUpdateQueue.Free;
40FLock.Free;
41inherited Destroy;
42end;
43
44procedure TUIUpdateDispatcher.PostUpdate(AUpdateEvent: TUIUpdateEvent);
45begin
46if AUpdateEvent = nil then
47Exit;
48
49FLock.Enter;
50try
51FUpdateQueue.Enqueue(AUpdateEvent);
52finally
53FLock.Leave;
54end;
55end;
56
57procedure TUIUpdateDispatcher.CheckAndProcessUpdates;
58begin
59// This method should be called periodically from the main UI thread
60// (e.g., in a TTimer's OnTimer event or message loop hook)
61if GetCurrentThreadID = FMainThreadID then
62ProcessUpdateQueue
63else
64// Error: Called from a non-UI thread
65// Log or raise an exception
66end;
67end;
68
69procedure TUIUpdateDispatcher.ProcessUpdateQueue;
70var
71UpdateEvent: TUIUpdateEvent;
72begin
73while True do
74begin
75FLock.Enter;
76try
77if FUpdateQueue.IsEmpty then
78Break; // No more updates
79
80UpdateEvent := FUpdateQueue.Dequeue;
81finally
82FLock.Leave;
83end;
84
85// Execute the update event on the UI thread
86try
87UpdateEvent.ExecuteOnUIThread;
88finally
89UpdateEvent.Free; // Free the event after execution
90end;
91end;
92end;
93
94// Example TUIUpdateEvent implementation
95type
96TUpdateLabelEvent = class(TUIUpdateEvent)
97private
98FLabel: TLabel;
99FNewText: string;
100public
101constructor Create(ALabel: TLabel; ANewText: string);
102procedure ExecuteOnUIThread;
103end;
104
105constructor TUpdateLabelEvent.Create(ALabel: TLabel; ANewText: string);
106begin
107inherited Create;
108FLabel := ALabel;
109FNewText := ANewText;
110end;
111
112procedure TUpdateLabelEvent.ExecuteOnUIThread;
113begin
114// This code is guaranteed to run on the main UI thread
115if Assigned(FLabel) and FLabel.HandleAllocated then
116begin
117FLabel.Caption := FNewText;
118end;
119end;
120
121// Example usage in a background thread:
122// var
123// Dispatcher: TUIUpdateDispatcher;
124// MyLabel: TLabel;
125// begin
126// Dispatcher := TUIUpdateDispatcher.Create;
127// MyLabel := TLabel.Create(Self);
128// MyLabel.Parent := Self;
129// // ... in a background thread ...
130// Dispatcher.PostUpdate(TUpdateLabelEvent.Create(MyLabel, 'Updated from background'));
131// // ... periodically call Dispatcher.CheckAndProcessUpdates from the main thread ...
132// end;
Algorithm description viewbox

Delphi Event-Driven UI Update Mechanism

Algorithm description:

This Delphi code implements a robust event-driven mechanism for safely updating UI elements from background threads. It uses a `TUIUpdateDispatcher` to manage a queue of `TUIUpdateEvent` objects. Background threads post update requests (as `TUIUpdateEvent` descendants) to the dispatcher. The dispatcher's `CheckAndProcessUpdates` method, which must be called from the main UI thread (e.g., via a timer or message hook), dequeues and executes these events. This ensures that all UI modifications happen on the correct thread, preventing threading errors and maintaining application stability.

Algorithm explanation:

The `TUIUpdateDispatcher` uses a `TQueue<TUIUpdateEvent>` to hold pending UI updates and a `TCriticalSection` for thread-safe enqueuing. The `FMainThreadID` stores the ID of the main UI thread. `PostUpdate` adds an event to the queue, protected by the lock. `CheckAndProcessUpdates` is designed to be called from the main UI thread; it verifies the thread ID and then calls `ProcessUpdateQueue`. `ProcessUpdateQueue` dequeues events and calls their `ExecuteOnUIThread` method. This method is intended to be implemented by derived event classes (e.g., `TUpdateLabelEvent`) to perform the actual UI manipulation. Crucially, `ExecuteOnUIThread` is guaranteed to run on the main thread because `ProcessUpdateQueue` is only invoked there. The destructor cleans up the queue and any remaining events. Time complexity for `PostUpdate` is O(1) on average. `CheckAndProcessUpdates` and `ProcessUpdateQueue` have a complexity of O(N) where N is the number of updates processed. Space complexity is O(N) to store the update events.

Pseudocode:

CLASS TUIUpdateEvent:
  METHOD ExecuteOnUIThread()
END CLASS

CLASS TUIUpdateDispatcher:
  UpdateQueue (Queue of TUIUpdateEvent)
  Lock (CriticalSection)
  MainThreadID (ThreadID)

  METHOD Create():
    Initialize UpdateQueue, Lock
    Set MainThreadID = CurrentThreadID
  END METHOD

  METHOD Destroy():
    WHILE UpdateQueue is NOT empty DO
      Dequeue Event
      Free Event
    END WHILE
    Free UpdateQueue and Lock
  END METHOD

  METHOD PostUpdate(UpdateEvent):
    Acquire Lock
    Enqueue UpdateEvent
    Release Lock
  END METHOD

  METHOD CheckAndProcessUpdates():
    IF CurrentThreadID == MainThreadID THEN
      Call ProcessUpdateQueue
    ELSE
      Log "Called from non-UI thread"
    END IF
  END METHOD

  METHOD ProcessUpdateQueue():
    LOOP FOREVER:
      Acquire Lock
      IF UpdateQueue is empty THEN
        Release Lock
        BREAK LOOP
      END IF
      Dequeue UpdateEvent
      Release Lock

      Execute UpdateEvent.ExecuteOnUIThread()
      Free UpdateEvent
    END LOOP
  END METHOD
END CLASS