Closed. This question needs to be more focused。它当前不接受答案。












想改善这个问题吗?更新问题,使其仅关注editing this post的一个问题。

6年前关闭。



Improve this question




我是Delphi的noobie,所以对任何愚蠢的问题感到抱歉。

我的主管向我解释说Application.ProcessMessages可以防止应用程序冻结并分配一些额外的计算时间。但是在此命令的文档中,总是有关于已处理的队列系统的某些说明?
请有人能解释一下我的情况吗?

最佳答案

没有捷径可以正确回答这个问题。

Windows应用程序与操作系统交互的主要方式是通过消息传递系统。 Windows应用程序中发生的所有事情都是响应消息而发生的。

例如:

如果您在屏幕上单击,则操作系统将决定单击哪个应用程序,然后向该应用程序发布一条消息,指示该应用程序已收到单击(以及该单击的位置)。

如果移动了窗口并在其下面显示了应用程序的一部分,则操作系统会发送一条消息,告诉您的应用程序重新绘制自身。

list 继续。发生的一切都是由消息驱动的。

现在,每个应用程序都有一个主要的用户界面线程(“Main”线程),并且该线程具有一个主要功能-它在无限循环中运行,该循环检查来自操作系统的这些消息,然后执行必要的代码以响应这些消息。

问题

您随即开始编写应用程序。您可能会编写如下代码:

procedure TForm1.Button1Click(Sender: TObject);
var i : Integer;
begin
  for i := 0 to 99999999999 do begin
    SolveTheProblemsOfTheWorld(i);
    CalculatePiToABillionPlaces;
  end;
end;

在程序的较大结构中,主线程中的执行如下所示:
  • 检查消息
  • 对于每个消息-执行相关的处理程序
  • 返回到“检查消息(循环)”

  • 因此,当相关处理程序之一(上面的Button1Click)突然开始花费很长时间才能完成时,此循环很高兴。要理解的关键是一个消息处理程序必须先完成,然后才能运行下一个。例如,如果单击滚动条并将其拖动,但已将一个处理程序附加到滚动条的OnClick上,该处理程序需要10秒钟才能完成,则在该单击处理程序完成之前,应用程序将看不到拖动操作。同时,消息队列已满,主线程对此没有任何处理。

    当然,您已经经历过-突然,您的应用程序无法响应点击。您无法与之交互,也无法移动该窗口,如果在其顶部拖动另一个窗口,该应用程序甚至不会重新绘制自身-它只会填满留在其上的所有垃圾。

    输入ProcessMessages

    不将长时间运行的代码放入线程的懒惰,可怕的解决方案

    当您调用Application.ProcessMessages时,您正在做的事情是,在这些处理程序之一的中间,指示主线程休息一下以返回检查消息队列并清空所有已堆积的消息。处理任何单击,窗口移动,输入,击键,并在需要时重绘(repaint)自身,等等。
    procedure TForm1.Button1Click(Sender: TObject);
    var i : Integer;
    begin
      for i := 0 to 99999999999 do begin
        SolveTheProblemsOfTheWorld(i);
        CalculatePiToABillionPlaces;
        Application.ProcessMessages;
      end;
    end;
    

    从表面上看,这似乎是明智的选择,因为它使您可以在长时间运行的循环中保持应用程序的响应速度。然而,最终,由于许多非常好的原因,这种编程风格被广泛认为是极差的实践。可以说,在任何想使用Application.ProcessMessages的地方,都是将工作转移到后台线程的可靠案例。

    有关更多详细信息,让我们看一下实际代码:
    procedure TApplication.ProcessMessages;
    var
      Msg: TMsg;
    begin
      while ProcessMessage(Msg) do {loop};
    end;
    

    因此,当您对Application.ProcessMessages进行调用时,您正在运行一个循环,即一个循环地清空消息队列中的消息(并执行附加到对这些消息作出反应的处理程序上的所有代码),直到其为空。当它为空并且没有更多消息要处理时,控制权将返回到程序的下一行。

    最重要的一点是,使用程序时所经历的流畅,流畅的交互是一种完全的错觉,而这完全取决于尽快处理此消息循环。将消息发布到您的应用程序与处理该消息之间的时间延迟越短,您的应用程序将感觉越活跃并能够响应。

    因此,附加到用户界面处理程序的所有代码都应快速运行。长时间运行的操作要么需要中断,以便消息处理可以继续(即:Application.ProcessMessages),要么这些操作需要移到一个单独的线程中,在其中他们可以执行而无需占用主线程并使它脱离主要职责(是为了使用户界面保持 Activity 状态)。

    有关该主题的非常好的文章,请参见:

    Peter Under的 A Key's Odyssey

    (Internet Archive link ...如果上述死亡)

    摘要:本文遵循通过VCL发送按键消息的路径。您将学习如何执行密钥处理,OnKey事件如何工作以及在整个过程中可以找到程序员的哪些干预点。此外,还说明了诸如消息处理之类的内容,您将学习如何在调试器中从消息循环到其最终目标跟踪消息。

    关于delphi - 我不明白Delphi中的Application.ProcessMessages在做什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25181713/

    10-08 22:41