1

我正在尝试以下代码。但是,如果我在此代码运行时单击表单的关闭按钮,则不会发生任何事情。我该如何纠正?即使在执行此循环时,我也需要关闭表单。

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 9999999 do
  begin
    Memo1.Lines.Add('hi');
    Application.ProcessMessages;
  end;
end;
4

3 回答 3

14

看看里面发生了什么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,从柜台上敲几个数量级,然后快速连续单击按钮两到三下并观察输出......

于 2013-06-04T16:29:31.123 回答
6

检查应用程序终止:

  for i := 0 to 9999999 do
  begin
    Memo1.Lines.Add('hi');
    Application.ProcessMessages;
    if Application.Terminated then Exit;
  end;
于 2013-06-04T16:26:30.043 回答
1

您需要在线程中运行任何紧密循环。这将解决问题。

但是如果你想保持代码不变,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;
于 2015-08-27T11:58:09.413 回答