我正在尝试以下代码。但是,如果我在此代码运行时单击表单的关闭按钮,则不会发生任何事情。我该如何纠正?即使在执行此循环时,我也需要关闭表单。
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 9999999 do
begin
Memo1.Lines.Add('hi');
Application.ProcessMessages;
end;
end;
我正在尝试以下代码。但是,如果我在此代码运行时单击表单的关闭按钮,则不会发生任何事情。我该如何纠正?即使在执行此循环时,我也需要关闭表单。
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 9999999 do
begin
Memo1.Lines.Add('hi');
Application.ProcessMessages;
end;
end;
看看里面发生了什么Application.ProcessMessages
。
当您关闭主窗体时,Windows会向WM_QUIT
程序发送一条消息。的相关部分TApplication.ProcessMessages
如下所示:
if Msg.Message <> WM_QUIT then
begin
//skipped
end
else
begin
{$IF DEFINED(CLR)}
if Assigned(FOnShutDown) then FOnShutDown(self);
DoneApplication;
{$IFEND}
FTerminate := True;
end;
我假设这不是一个 CLR 程序,所以此时唯一发生的事情就是设置FTerminate := True
. Application
这反映在Application.Terminated
财产上。
当应用程序关闭时,它为了安全关闭所做的事情之一就是等待所有线程完成。这段代码恰好在主线程中运行,但原理在任何线程中都是相同的:如果您正在执行可能必须提前完成的长时间运行的任务,则必须明确检查是否提前终止。
知道了这一点,很容易弄清楚如何修复你的代码:
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 9999999 do
begin
Memo1.Lines.Add('hi');
Application.ProcessMessages;
if Application.Terminated then
Break;
end;
end;
另外,首先要小心使用Application.ProcessMessages
,因为它会处理应用程序的所有消息。对于可能出错的简单想法,请尝试添加IntToStr(i)
而不是'hi'
to Memo1.Lines
,从柜台上敲几个数量级,然后快速连续单击按钮两到三下并观察输出......
检查应用程序终止:
for i := 0 to 9999999 do
begin
Memo1.Lines.Add('hi');
Application.ProcessMessages;
if Application.Terminated then Exit;
end;
您需要在线程中运行任何紧密循环。这将解决问题。
但是如果你想保持代码不变,Application.ProcessMessages 会让你的循环非常慢。所以你需要不那么频繁地运行 Application.ProcessMessages :
Counter:= 0;
for i := 0 to 9999999 do
begin
DoSomeStuff;
{ Prevent freeze }
inc(Counter);
if counter > 10000 then
begin
Counter:= 0;
Application.ProcessMessages;
if Application.Terminated then Exit;
end;
end;