如何从 TThread 显示“请稍候”模态表单并在工作完成后释放它?

Sam*_*ami 2 delphi multithreading modal-dialog delphi-10-seattle

我已经工作了一段时间,试图制作一个模态表单来通知用户等待工作结束。这是我正在尝试做的一个简单示例:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  TLoader = class(TThread)
    private
      FStrings: TStrings;
      procedure ShowWait;
      procedure EndsWait;
    public
      Constructor Create(AStrings: TStrings);
      Destructor Destroy; override;
      procedure Execute; override;
  end;
var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
Var
  List: TStrings;
begin
  List := TStringList.Create;
  try
    // Load Some Data here
    TLoader.Create(List);
  finally
    List.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

{ TLoader }

constructor TLoader.Create(AStrings: TStrings);
begin
  inherited Create;
  FreeOnTerminate:= True;
  FStrings:= TStringList.Create;
  FStrings.AddStrings(AStrings);
end;

destructor TLoader.Destroy;
begin
  FStrings.Free;
  inherited;
end;

procedure TLoader.EndsWait;
begin
  TForm(Application.FindComponent('FWait')).Free;
end;

procedure TLoader.Execute;
begin
  inherited;
  Synchronize(ShowWait);
  // Do Some Job while not terminated
  Sleep(1000);
  // Free Wait Form
  // This part is not working
  Synchronize(EndsWait);
end;

procedure TLoader.ShowWait;
begin
  With TForm.Create(Application) do
    begin
      // Some code
      Name:= 'FWait';
      ShowModal;
    end;
end;

end.
Run Code Online (Sandbox Code Playgroud)

一切都按我的预期工作,除了Synchronize(EndsWait);没有关闭和释放模态表单。

如何在 aTThread运行时显示模态表单并在TThread终止时释放它?


更新:

我已经尝试按照 Remy 的建议进行如下操作:

type
  TForm2 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  TLoader = class(TThread)
    protected
      procedure DoTerminate; override;
      procedure DoCloseModal;
    public
      constructor Create;
      procedure Execute; override;
  end;
var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TLoader }

constructor TLoader.Create;
begin
  inherited Create;
  FreeOnTerminate:= True;
end;

procedure TLoader.DoCloseModal;
begin
  Form2.ModalResult:= mrOk;
end;

procedure TLoader.DoTerminate;
begin
  inherited DoTerminate;
  Synchronize(DoCloseModal);
end;

procedure TLoader.Execute;
begin
  inherited;
  Sleep(200);
end;

procedure TForm2.FormShow(Sender: TObject);
begin
  TLoader.Create;
end;

end.
Run Code Online (Sandbox Code Playgroud)

主窗体按钮单击事件处理程序:

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm2.Create(nil) do
    try
      ShowModal;
    finally
      Free;
    end;
end;
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 6

你有两个选择:

  1. 不要使用模态形式开始。TThread.Synchronize()在同步方法退出之前阻止您的线程,但TForm.ShowModal()在表单关闭之前阻止该方法。使用TThread.Synchronize()(或更好,TThread.Queue()Create()+ Show()(不是ShowModal())Wait Form,然后返回到线程并让它根据需要完成它的工作,然后Synchronize()/Queue()再次(或使用线程的OnTerminate事件)在完成后Close()+ Free()Wait Form。

  2. 或者,如果您想使用模态等待表单,则根本不要让线程管理等待表单。让您的按钮OnClick处理程序Create()+ ShowModal()(不是Show())等待表单,并Free()ShowModal()退出时使用它。当等待表单显示和关闭时,让等待表单在内部创建和终止线程。如果线程在 Wait Form 关闭之前结束,则线程的OnTerminate处理程序可以处理Close()Form(它只是设置 Form 的ModalResult),以便ShowModal()将在OnClick处理程序中退出。