Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8155557
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 6, 20262026-06-06T16:42:10+00:00 2026-06-06T16:42:10+00:00

I’ve always wondered is there a better way that I should be writing some

  • 0

I’ve always wondered is there a better way that I should be writing some of my procedures, particularly ones that take a long time to finish.

I have always run everything off the Main GUI Thread which I now understand and realise is bad because it will make the Application unresponsive, Application.ProcessMessages will not really help here.

This makes me think I need to use TThreads for lengthy operations such as copying a file for example. This is also made me wonder how some Applications give you full control, eg allow you to pause, resume and or stop the operation.

I have about 3 lengthy operations in a personal project I am working on which I display a dialog form with a TProgressBar on. Whilst this does work, I feel it could be done much better. These progress dialogs could be shown for such a long time that you may want to cancel the operation and instead finish the job later.

As I said, currently I am running of the Main Gui Thread, do I instead need to use TThreads? I am not sure how or where to start implementing them as I have not worked with them before. If I do need threads do they offer what I need such as pausing, resuming, stopping an operation etc?

Basically I am looking for a better way of handling and managing lengthy operations.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-06T16:42:11+00:00Added an answer on June 6, 2026 at 4:42 pm

    Yes, this is definitely a case where you need a thread to do the task.

    A little example how to pause/resume a thread and cancel the thread.

    Progress is sent to the main thread through a PostMessage call.
    The pause/resume and cancel are made with TSimpleEvent signals.

    Edit: As per the comments from @mghie, here is a more complete example:

    Edit 2: Showing how to pass a procedure for the thread to call for the heavy work.

    Edit 3: Added some more features and a test unit.

    unit WorkerThread;
    
    interface
    
    uses Windows, Classes, SyncObjs;
    
    type
      TWorkFunction = function: boolean of object;
    
      TWorkerThread = Class(TThread)
      private
        FCancelFlag: TSimpleEvent;
        FDoWorkFlag: TSimpleEvent;
        FOwnerFormHandle: HWND;
        FWorkFunc: TWorkFunction; // Function method to call
        FCallbackMsg: integer; // PostMessage id
        FProgress: integer;
        procedure SetPaused(doPause: boolean);
        function GetPaused: boolean;
        procedure Execute; override;
      public
        Constructor Create(WindowHandle: HWND; callbackMsg: integer;
          myWorkFunc: TWorkFunction);
        Destructor Destroy; override;
        function StartNewWork(newWorkFunc: TWorkFunction): boolean;
        property Paused: boolean read GetPaused write SetPaused;
      end;
    
    implementation
    
    constructor TWorkerThread.Create(WindowHandle: HWND; callbackMsg: integer;
      myWorkFunc: TWorkFunction);
    begin
      inherited Create(false);
      FOwnerFormHandle := WindowHandle;
      FDoWorkFlag := TSimpleEvent.Create;
      FCancelFlag := TSimpleEvent.Create;
      FWorkFunc := myWorkFunc;
      FCallbackMsg := callbackMsg;
      Self.FreeOnTerminate := false; // Main thread controls for thread destruction
      if Assigned(FWorkFunc) then
        FDoWorkFlag.SetEvent; // Activate work at start
    end;
    
    destructor TWorkerThread.Destroy; // Call MyWorkerThread.Free to cancel the thread
    begin
      FDoWorkFlag.ResetEvent; // Stop ongoing work
      FCancelFlag.SetEvent; // Set cancel flag
      Waitfor; // Synchronize
      FCancelFlag.Free;
      FDoWorkFlag.Free;
      inherited;
    end;
    
    procedure TWorkerThread.SetPaused(doPause: boolean);
    begin
      if doPause then
        FDoWorkFlag.ResetEvent
      else
        FDoWorkFlag.SetEvent;
    end;
    
    function TWorkerThread.StartNewWork(newWorkFunc: TWorkFunction): boolean;
    begin
      Result := Self.Paused; // Must be paused !
      if Result then
      begin
        FWorkFunc := newWorkFunc;
        FProgress := 0; // Reset progress counter
        if Assigned(FWorkFunc) then
          FDoWorkFlag.SetEvent; // Start work
      end;
    end;
    
    procedure TWorkerThread.Execute;
    {- PostMessage LParam:
      0 : Work in progress, progress counter in WParam
      1 : Work is ready
      2 : Thread is closing
    }
    var
      readyFlag: boolean;
      waitList: array [0 .. 1] of THandle;
    begin
      FProgress := 0;
      waitList[0] := FDoWorkFlag.Handle;
      waitList[1] := FCancelFlag.Handle;
      while not Terminated do
      begin
        if (WaitForMultipleObjects(2, @waitList[0], false, INFINITE) <>
          WAIT_OBJECT_0) then
          break; // Terminate thread when FCancelFlag is signaled
        // Do some work
        readyFlag := FWorkFunc;
        if readyFlag then // work is done, pause thread
          Self.Paused := true;
        Inc(FProgress);
        // Inform main thread about progress
        PostMessage(FOwnerFormHandle, FCallbackMsg, WPARAM(FProgress),
          LPARAM(readyFlag));
      end;
      PostMessage(FOwnerFormHandle, FCallbackMsg, 0, LPARAM(2)); // Closing thread
    end;
    
    function TWorkerThread.GetPaused: boolean;
    begin
      Result := (FDoWorkFlag.Waitfor(0) <> wrSignaled);
    end;
    
    end.
    

    Just call MyThread.Paused := true to pause and MyThread.Paused := false to resume the thread operation.

    To cancel the thread, call MyThread.Free.

    To receive the posted messages from the thread, see following example:

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, WorkerThread;
    
    const
      WM_MyProgress = WM_USER + 0; // The unique message id
    
    type
      TForm1 = class(TForm)
        Label1: TLabel;
        btnStartTask: TButton;
        btnPauseResume: TButton;
        btnCancelTask: TButton;
        Label2: TLabel;
        procedure btnStartTaskClick(Sender: TObject);
        procedure btnPauseResumeClick(Sender: TObject);
        procedure btnCancelTaskClick(Sender: TObject);
      private
        { Private declarations }
        MyThread: TWorkerThread;
        workLoopIx: integer;
    
        function HeavyWork: boolean;
        procedure OnMyProgressMsg(var Msg: TMessage); message WM_MyProgress;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TForm1 }
    const
      cWorkLoopMax = 500;
    
    function TForm1.HeavyWork: boolean; // True when ready
    var
      i, j: integer;
    begin
      j := 0;
      for i := 0 to 10000000 do
        Inc(j);
      Inc(workLoopIx);
      Result := (workLoopIx >= cWorkLoopMax);
    end;
    
    procedure TForm1.btnStartTaskClick(Sender: TObject);
    begin
      if not Assigned(MyThread) then
      begin
        workLoopIx := 0;
        btnStartTask.Enabled := false;
        btnPauseResume.Enabled := true;
        btnCancelTask.Enabled := true;
        MyThread := TWorkerThread.Create(Self.Handle, WM_MyProgress, HeavyWork);
      end;
    end;
    
    procedure TForm1.btnPauseResumeClick(Sender: TObject);
    begin
      if Assigned(MyThread) then
        MyThread.Paused := not MyThread.Paused;
    end;
    
    procedure TForm1.btnCancelTaskClick(Sender: TObject);
    begin
      if Assigned(MyThread) then
      begin
        FreeAndNil(MyThread);
        btnStartTask.Enabled := true;
        btnPauseResume.Enabled := false;
        btnCancelTask.Enabled := false;
      end;
    end;
    
    procedure TForm1.OnMyProgressMsg(var Msg: TMessage);
    begin
      Msg.Msg := 1;
      case Msg.LParam of
        0:
          Label1.Caption := Format('%5.1f %%', [100.0 * Msg.WParam / cWorkLoopMax]);
        1:
          begin
            Label1.Caption := 'Task done';
            btnCancelTaskClick(Self);
          end;
        2:
          Label1.Caption := 'Task terminated';
      end;
    end;
    
    end.
    

    And the form:

    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 163
      ClientWidth = 328
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -13
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      PixelsPerInch = 120
      TextHeight = 16
      object Label1: TLabel
        Left = 79
        Top = 18
        Width = 51
        Height = 16
        Caption = 'Task idle'
      end
      object Label2: TLabel
        Left = 32
        Top = 18
        Width = 41
        Height = 16
        Caption = 'Status:'
      end
      object btnStartTask: TButton
        Left = 32
        Top = 40
        Width = 137
        Height = 25
        Caption = 'Start'
        TabOrder = 0
        OnClick = btnStartTaskClick
      end
      object btnPauseResume: TButton
        Left = 32
        Top = 71
        Width = 137
        Height = 25
        Caption = 'Pause/Resume'
        Enabled = False
        TabOrder = 1
        OnClick = btnPauseResumeClick
      end
      object btnCancelTask: TButton
        Left = 32
        Top = 102
        Width = 137
        Height = 25
        Caption = 'Cancel'
        Enabled = False
        TabOrder = 2
        OnClick = btnCancelTaskClick
      end
    end
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I know there's a lot of other questions out there that deal with this
link Im having trouble converting the html entites into html characters, (&# 8217;) i
That's pretty much it. I'm using Nokogiri to scrape a web page what has
I have just tried to save a simple *.rtf file with some websites and
For some reason, after submitting a string like this Jack’s Spindle from a text
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
I've got a string that has curly quotes in it. I'd like to replace
I have a French site that I want to parse, but am running into
I am doing a simple coin flipping experiment for class that involves flipping a

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.