1. Home
  2. Computing & Technology
  3. Delphi Programming

Synchronizing Threads and GUI in Delphi application

By , About.com Guide

Synchronizing Threads and GUI

Synchronizing Threads and GUI

Code submitted by Jens Borrisholt

Multi-threading in Delphi lets you create applications that include several simultaneous paths of execution.

A "normal" Delphi application is single-threaded: all (VCL) objects access their properties and execute their methods within this single thread.

Threads and GUI

To speed up data processing in your application you can decide to include one or more "secondary" threads.

When several threads are running in the application a question arises: how to update your GUI (user interface) as a result of a thread execution. The question lies in the TThread class Synchronize method.

To update your application's user interface - main thread - from a secondary thread you need to call the Synchronize method - a thread-safe method that avoids multi-threading conflicts that can arise from accessing object properties or methods that are not thread-safe, or using resources not in the main thread of execution.

An example demo uses several buttons with progress bar, each progress bar displaying the current "state" of the thread execution...

Download source code


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.
Explore Delphi Programming
About.com Special Features

Reader's Choice Award Winners

What are the best instant messengers, apps, editors and more? You told us, for our 2010 technology awards program. More >

iPad Central

Is Apple's new tablet computer impractical, a must-have -- or both? We'll help you figure it out. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming
  4. Coding Delphi Applications
  5. Threading in Delphi
  6. Synchronizing Threads and GUI in Delphi application

©2010 About.com, a part of The New York Times Company.

All rights reserved.