Synchronizing Threads and GUI in a Delphi Application

Sample Code for a GUI Delphi Application With Multiple Threads

Threads and GUI, Multi-threading in Delphi helps you to create packages that consist of several simultaneous paths of execution.

A normal Delphi utility is unmarried-threaded, which means all VCL objects get entry to their properties and execute their methods within this single thread. To accelerate facts processing for your software, consist of one or extra secondary threads.

Processor Threads

A thread is a verbal exchange channel from an application to a processor. Single-threaded programs want verbal exchange to go with the flow in both guidelines (to and from the processor).

Because it executes; multi-threaded apps can open several unique channels, consequently dashing up execution.

Threads & GUI

When numerous threads are jogging inside the software, the query arises of the way you could replace your graphical consumer interface as a result of a thread execution. The answer lies inside the TThread class Synchronize approach.

To replace your utility’s user interface, or major thread, from a secondary thread, you need to call the Synchronize technique. This technique is a thread-safe approach that avoids multi-threading conflicts which can arise from accessing item residences or methods that are not thread-secure, or the usage of resources no longer inside the essential thread of execution.

Below is an instance demo that uses numerous buttons with development bars, every development bar displaying the cutting-edge “state” of the thread execution.

unit MainU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, ExtCtrls;
type
//interceptor class
TButton = class(StdCtrls.TButton)
OwnedThread: TThread;
ProgressBar: TProgressBar;
end;
TMyThread = class(TThread)
private
FCounter: Integer;
FCountTo: Integer;
FProgressBar: TProgressBar;
FOwnerButton: TButton;
procedure DoProgress;
procedure SetCountTo(const Value: Integer) ;
procedure SetProgressBar(const Value: TProgressBar) ;
procedure SetOwnerButton(const Value: TButton) ;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean) ;
property CountTo: Integer read FCountTo write SetCountTo;
property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;
property OwnerButton: TButton read FOwnerButton write SetOwnerButton;
end;
TMainForm = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Button2: TButton;
ProgressBar2: TProgressBar;
Button3: TButton;
ProgressBar3: TProgressBar;
Button4: TButton;
ProgressBar4: TProgressBar;
Button5: TButton;
ProgressBar5: TProgressBar;
procedure Button1Click(Sender: TObject) ;
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
{ TMyThread }
constructor TMyThread.Create(CreateSuspended: Boolean) ;
begin
inherited;
FCounter := 0;
FCountTo := MAXINT;
end;
procedure TMyThread.DoProgress;
var
PctDone: Extended;
begin
PctDone := (FCounter / FCountTo) ;
FProgressBar.Position := Round(FProgressBar.Step * PctDone) ;
FOwnerButton.Caption := FormatFloat('0.00 %', PctDone * 100) ;
end;
procedure TMyThread.Execute;
const
Interval = 1000000;
begin
FreeOnTerminate := True;
FProgressBar.Max := FCountTo div Interval;
FProgressBar.Step := FProgressBar.Max;
while FCounter < FCountTo do
begin
if FCounter mod Interval = 0 then Synchronize(DoProgress) ;
Inc(FCounter) ;
end;
FOwnerButton.Caption := 'Start';
FOwnerButton.OwnedThread := nil;
FProgressBar.Position := FProgressBar.Max;
end;
procedure TMyThread.SetCountTo(const Value: Integer) ;
begin
FCountTo := Value;
end;
procedure TMyThread.SetOwnerButton(const Value: TButton) ;
begin
FOwnerButton := Value;
end;
procedure TMyThread.SetProgressBar(const Value: TProgressBar) ;
begin
FProgressBar := Value;
end;
procedure TMainForm.Button1Click(Sender: TObject) ;
var
aButton: TButton;
aThread: TMyThread;
aProgressBar: TProgressBar;
begin
aButton := TButton(Sender) ;
if not Assigned(aButton.OwnedThread) then
begin
aThread := TMyThread.Create(True) ;
aButton.OwnedThread := aThread;
aProgressBar := TProgressBar(FindComponent(StringReplace(aButton.Name, 'Button', 'ProgressBar', []))) ;
aThread.ProgressBar := aProgressBar;
aThread.OwnerButton := aButton;
aThread.Resume;
aButton.Caption := 'Pause';
end
else
begin
if aButton.OwnedThread.Suspended then
aButton.OwnedThread.Resume
else
aButton.OwnedThread.Suspend;
aButton.Caption := 'Run';
end;
end;
end.

Thanks to Jens Borrisholt for submitting this code sample.

summary

A normal Delphi utility is unmarried-threaded, which means all VCL objects get entry to their properties and execute their methods within this single thread. Because it executes; multi-threaded apps can open several unique channels, consequently dashing up execution. To replace your utility’s user interface, or major thread, from a secondary thread, you need to call the Synchronize technique. This technique is a thread-safe approach that avoids multi-threading conflicts