当在Delphi中运行一个巨大的for循环时,为什么'form close'事件没有发生?

时间:2013-06-04 16:17:21

标签: performance delphi delphi-xe2 pascal

我正在尝试以下代码。但是,如果在此代码运行时单击窗体的关闭按钮,则不会发生任何操作。我怎么能纠正这个?即使执行此循环,我也需要关闭表单。

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

3 个答案:

答案 0 :(得分:13)

查看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'添加到Memo1.Lines,从柜台上敲几个数量级,然后点击两三个按钮快速连续几次看输出......

答案 1 :(得分:6)

检查申请已终止:

  for i := 0 to 9999999 do
  begin
    Memo1.Lines.Add('hi');
    Application.ProcessMessages;
    if Application.Terminated then Exit;
  end;

答案 2 :(得分: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;