您應該做的是將工作線程從UI表單中分離出來。在TThread後裔中做你的工作。
兩者之間的所有通信都應通過發佈異步消息來完成。工作線程應該在啓動時向UI發佈消息,報告進度以及何時結束。用戶界面可以使用它來可視化表單,更新進度條並最終關閉表單。如果你需要在用戶界面上有一個用戶取消按鈕,這應該發佈一條消息給它用來中止執行的工作線程。通過「發佈異步消息」我的意思是你應該使用其他RTL.Messaging(它只處理同步消息)或至少將調用包裝在TThread.Queue中的消息框架。我會通過我的消息傳遞課程here進行所有消息傳遞。
要處理我自己使用這個基類的工作:
TMEBatchOp = Class(TMELocalizableComponent)
Private
FMessageHandler: TMEMessageHandler;
FInfo: TMEBatchOpInfo;
FLastUpdateStatus: Cardinal;
FRequestedCancel: Boolean;
Procedure CheckCancelled;
Procedure Run;
Procedure SetResult(Const Value: TMEBatchOpResult);
Procedure SetStatus(Const Value: TMEBatchOpStatus);
Procedure UpdateStatus(Const DelaySecs: Integer = 0);
Protected
Function CalcWorkMax: Integer; Virtual;
Procedure DoExecute; Virtual; Abstract;
Procedure DoSetup; Virtual;
Procedure DoTeardown; Virtual;
Function GetAllowCancel: Boolean; Virtual;
Function GetDescription: String; Virtual;
Procedure ReceiveEnvelope(Const Envelope: TMEMessageEnvelope);
Property MessageHandler: TMEMessageHandler Read FMessageHandler;
Property Info: TMEBatchOpInfo Read FInfo;
Property RequestedCancel: Boolean Read FRequestedCancel;
Public
Class Procedure CaptureLocalizable(Localizer: TMELocalizer); Override;
Class Function GetModuleName: String;
Constructor Create(AOwner: TComponent); Override;
Procedure Worked(Qty: Integer = 1);
End;
具體的工作線程的實現需要定義TMEBatchOp的子類,並實現DoExecute方法。如果需要,也可以重新定義CalcWorkMax,DoSetup和DoTeardown。例如:
Type
TBatchOpSaveTexts = Class(TMEBatchOp)
Protected
Function CalcWorkMax: Integer; Override;
Procedure DoExecute; Override;
Function GetDescription: String; Override;
Public
Class Procedure CaptureLocalizable(Localizer: TMELocalizer); Override;
End;
執行這只是需要這樣一個電話:
RunAndFree(TBatchOpSaveTexts);
凡RunAndFree是這樣實現的:
Function RunAndFree(BatchOpClass: TMEBatchOpClass): TMEBatchOpResult; Overload;
Begin
Result := RunAndFree(BatchOpClass.Create(Nil));
End;
Function RunAndFree(BatchOp: TMEBatchOp): TMEBatchOpResult; Overload;
Begin
Try
BatchOp.Run;
Result := BatchOp.Info.Result;
Finally
BatchOp.Free;
End;
End;
TMEBatchOpInfo包含工作結果和狀態信息,倍並完成工作,並做和進步。它還包含有關操作是否可以取消的信息。所有消息都包含此信息的副本,因此UI可以相應地進行更新。下面是它的接口:
TMEBatchOpInfo = Class(TMEPersistent)
Private
FID: String;
FParentID: String;
FDescription: String;
FTimeBegin: TDateTime;
FTimeEnd: TDateTime;
FResult: TMEBatchOpResult;
FWorkMax: Integer;
FWorkDone: Integer;
FAllowCancel: Boolean;
FStatus: TMEBatchOpStatus;
Function GetDone: Boolean;
Public
Constructor Create; Override;
Procedure Assign(Source: TPersistent); Override;
Property ID: String Read FID;
Property ParentID: String Read FID;
Property Description: String Read FDescription;
Property TimeBegin: TDateTime Read FTimeBegin;
Property TimeEnd: TDateTime Read FTimeEnd;
Property Result: TMEBatchOpResult Read FResult;
Property WorkMax: Integer Read FWorkMax;
Property WorkDone: Integer Read FWorkDone;
Property Done: Boolean Read GetDone;
Property AllowCancel: Boolean Read FAllowCancel;
Property Status: TMEBatchOpStatus Read FStatus;
End;
不要做任何顯示之前的形式,全面,你不會有問題,將在主線程阻塞。 –
通常的解決方案是在OnShow的末尾發佈自定義消息給自己,然後在該消息的處理程序中開始處理。這允許首先處理所有其他消息。 –