multithreading - 如何从 TThread 显示“请稍候”模式表单并在工作完成后释放它?
问题描述
我已经工作了一段时间,试图制作一个模态表单来通知用户等到工作结束。这是我正在尝试做的一个简单示例:
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.
一切都按我的预期工作,除了Synchronize(EndsWait);
没有关闭和释放模态表单。
如何在运行时显示模态表单并在终止TThread
时释放它?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.
主窗体按钮单击事件处理程序:
procedure TForm1.Button1Click(Sender: TObject);
begin
with TForm2.Create(nil) do
try
ShowModal;
finally
Free;
end;
end;
解决方案
你有两个选择:
不要一开始就使用模态形式。
TThread.Synchronize()
阻塞你的线程直到同步的方法退出,但TForm.ShowModal()
阻塞该方法直到窗体关闭。使用TThread.Synchronize()
(或更好,TThread.Queue()
)Create()
+Show()
(不是ShowModal()
)等待表单,然后返回线程并让它根据需要完成其工作,然后Synchronize()
/Queue()
再次(或使用线程的OnTerminate
事件)在完成后Close()
+Free()
等待表单。或者,如果您想使用模式等待表单,则根本不要让线程管理等待表单。让您的按钮
OnClick
处理程序Create()
+ShowModal()
(不是Show()
)等待表单,并Free()
在ShowModal()
退出时使用它。分别在显示和关闭等待表单时让等待表单在内部创建和终止线程。如果线程在等待窗体关闭之前结束,线程的OnTerminate
处理程序可以Close()
在窗体(它只是设置窗体ModalResult
)中ShowModal()
退出,以便在OnClick
处理程序中退出。
推荐阅读
- c++ - std::hardware_破坏性_干扰_大小在哪里?
- microstrategy - 当您创建一个自由形式的微观策略时,是否可以进行自动映射?
- powershell - 运行命令后 Windows PowerShell 保持光标
- c# - 使用 C# WinForms 更改电子邮件中图像的位置
- microsoft-teams - 通过输入冒号使用表情符号过早生成笑脸
- python - 以数据框的形式返回行,其中包含特定列中的一些单词
- javascript - 可点击的图片,可展开部分图片
- typescript - Typescript - 如何选择重载函数签名以从中获取参数类型?
- docker - Jenkins 管道中有多个代理,但在某些阶段使用一个代理
- laravel - 在 laravel 中生成多个随机代码并将其保存到数据库