Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Obviously, somewhere there has to be a reference to the instantiated thread. But I can relate to your wish: you want a always-done-never-care solution.</p> <p>I suggest you manage the thread's existence by a separate ThreadController class:</p> <pre><code>unit Unit2; interface uses Classes, SysUtils, Forms, Windows, Messages; type TMyThreadProgressEvent = procedure(Value: Integer; Proceed: Boolean) of object; procedure RunMyThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent); implementation type TMyThread = class(TThread) private FException: Exception; FOnProgress: TMyThreadProgressEvent; FProceed: Boolean; FValue: Integer; procedure DoProgress; procedure HandleException; procedure ShowException; protected procedure Execute; override; end; TMyThreadController = class(TObject) private FThreads: TList; procedure StartThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent); procedure ThreadTerminate(Sender: TObject); public constructor Create; destructor Destroy; override; end; var FMyThreadController: TMyThreadController; function MyThreadController: TMyThreadController; begin if not Assigned(FMyThreadController) then FMyThreadController := TMyThreadController.Create; Result := FMyThreadController end; procedure RunMyThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent); begin MyThreadController.StartThread(StartValue, OnProgress); end; { TMyThreadController } constructor TMyThreadController.Create; begin inherited; FThreads := TList.Create; end; destructor TMyThreadController.Destroy; var Thread: TThread; begin while FThreads.Count &gt; 0 do begin Thread := FThreads[0]; //Save reference because Terminate indirectly //extracts the list entry in OnTerminate! Thread.Terminate; //Indirectly decreases FThreads.Count Thread.Free; end; FThreads.Free; inherited Destroy; end; procedure TMyThreadController.StartThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent); var Thread: TMyThread; begin Thread := TMyThread.Create(True); FThreads.Add(Thread); //Add to list before a call to Resume because once //resumed, the thread might be gone already! Thread.FValue := StartValue; Thread.FOnProgress := OnProgress; Thread.OnTerminate := ThreadTerminate; Thread.Resume; end; procedure TMyThreadController.ThreadTerminate(Sender: TObject); begin FThreads.Extract(Sender); end; { TMyThread } procedure TMyThread.DoProgress; begin if (not Application.Terminated) and Assigned(FOnProgress) then FOnProgress(FValue, FProceed); end; procedure TMyThread.Execute; begin try FProceed := True; while (not Terminated) and (not Application.Terminated) and FProceed and (FValue &lt; 20) do begin Synchronize(DoProgress); if not FProceed then Break; Inc(FValue); Sleep(2000); end; //In case of normal execution ending, the thread may free itself. Otherwise, //the thread controller object frees the thread. if not Terminated then FreeOnTerminate := True; except HandleException; end; end; procedure TMyThread.HandleException; begin FException := Exception(ExceptObject); try if not (FException is EAbort) then Synchronize(ShowException); finally FException := nil; end; end; procedure TMyThread.ShowException; begin if GetCapture &lt;&gt; 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0); if (FException is Exception) and (not Application.Terminated) then Application.ShowException(FException) else SysUtils.ShowException(FException, nil); end; initialization finalization FreeAndNil(FMyThreadController); end. </code></pre> <p>To run this sample thread which counts from 5 to 19 in 2 second intervals and provides feedback and an opportunity to a premature termination, call from the main thread:</p> <pre><code>type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private procedure MyThreadProgress(Value: Integer; Proceed: Boolean); end; ... procedure TForm1.Button1Click(Sender: TObject); begin RunMyThread(5, MyThreadProgress); end; procedure TForm1.MyThreadProgress(Value: Integer; Proceed: Boolean); begin Caption := IntToStr(Value); end; </code></pre> <p>This thread automatically kills itself on either thread's or application's termination.</p> <p>Maybe this unit is a little overkill for your situation because it is capable of handling multiple threads (of the same type), but I think it answers your question. Adjust to your liking.</p> <p><sup>Partial origin of this answer: <a href="http://www.nldelphi.com/forum/showthread.php?t=24450" rel="nofollow">NLDelphi.com</a>.</sup></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload