【问题标题】:How to Prevent ProcessMessages in Delphi如何在 Delphi 中防止 ProcessMessages
【发布时间】:2010-11-18 02:39:26
【问题描述】:

Application.ProcessMessages 命令是众所周知的,我在长进程中使用它以确保我的程序不会占用计算机。

但我有一组相当快的处理,我将视图缓冲到文件中。在缓冲过程中,可能会发送一些系统消息(例如重绘或滚动条移动或其他事件)。我想防止这些被 ProcessMessages 处理,直到我的缓冲完成。

有什么办法:

  1. 在我的程序完成之前阻止 Application.ProcessMessages,或者

  2. 捕获在我的过程中生成的所有消息,直到过程结束才释放它们。

【问题讨论】:

  • 重读你的问题我不太明白——如果你有一个快速执行的程序并且不希望Application.ProcessMessages处理任何不受欢迎的消息,你为什么要打电话给Application.ProcessMessages这个程序?
  • mghie:我没有明确地调用它,但我确实将一些事件添加到队列中(例如滚动条位置),如果消息恰好得到处理,这些事件将被执行。我需要简单地确保在这段代码中,不会执行任何待处理的事件
  • 但这就是重点:如果您在您的过程中,除非您明确调用Application.ProcessMessages,否则将处理 no 事件。它们将被添加到队列中并稍后处理,仅此而已。除非您愿意,否则如何处理这些消息?

标签: delphi messages idle-processing


【解决方案1】:

即使ProcessMessages 发送您不想要的消息,也允许它继续运行不应被归类为有问题的。通过一些代码重构,您可以将缓冲方法移动到单独的线程中并从那里开始。

如果您试图将控件的“可视内容”复制到文件中,

  • 查看允许子控件将自己绘制成位图的 WM_PRINT(xxx) 消息
  • 尝试LockWindowUpdate Win32 API 方法调用,它将关闭所有对该控件的绘画消息
  • 如果需要,请覆盖控件类甚至父类上的 WndProc/DefaultWndProc 方法,并且只需为发送的每条消息返回“true”

覆盖 WndProcDefaultWndProc 并简单地为每条消息返回 true 基本上“关闭”ProcessMessages 但是这样做并不安全,因为控件可能需要处理一条或多条消息才能正常运行。

关闭ProcessMessages 是不可能的(不重写用于消息处理的VCL 代码),因为它是VCL 表单的消息循环构建方式的一部分。

【讨论】:

  • LockWindowUpdate 似乎是我想要的。你的其他想法也很好。谢谢。
  • 永远不应该使用 LockWindowUpdate() API,根据 Raymond Chen 的说法:blogs.msdn.com/oldnewthing/archive/2007/02/23/1747713.aspx 至少它不应该用于您想要使用它的目的:blogs.msdn.com/oldnewthing/archive/2007/02/22/1742084.aspx
  • 嗯。谢谢mghie。你的警告会被注意的。但迈克仍然给了我很多关于处理的信息,以引导我朝着正确的方向前进。
  • @mghie:永远不应该使用 LockWindowsUpdate。是的——我在等待同样有效的东西。使用 SetWindowUpdate 的行为似乎有所不同。我真的试着说不......布赖恩。
  • @Brian:“同样有效” - 如果LockWindowsUpdate() 真的不起作用,那怎么办?还有什么比这更糟的?或者更重要的是 - 你想做什么LockWindowsUpdate() 可以帮助你做而替代品没有?你对SetWindowUpdate() 有什么问题?
【解决方案2】:

捕获在我的过程中生成的所有消息,而不是释放它们 直到程序结束。

你可以做一个肮脏的黑客(只有当你想不出更好的方法时):

您可以使用Win32 Hooks 来查看(捕获)任何消息。
具体来说,使用 SetWindowsHookEx 和 WH_CALLWNDPROC 作为 idHook 值。
然后,您可以将它们记录到列表/队列中,并在需要时重新发送。

【讨论】:

  • 我认为这也可以。比迈克的想法多一点工作,但会让我完全控制。谢谢。
【解决方案3】:

我早在 Windows 2 中就了解到,Windows 消息会在您意想不到的时候发生。库的任何部分都可能导致您的应用程序的消息处理发生。与其阻止潮流,不如让你的代码在这种情况下变得健壮。这可能就像使用 BeginUpdate/EndUpdate 对一样简单,也可能更复杂(使用临时并在最后进行最终更新)。

【讨论】:

  • 这就是我正在寻找的东西:一个 BeginUpdate/EndUpdate 对,它将阻止所有 Windows 事件,直到工作完成。但我相信这些只能防止重新粉刷。
【解决方案4】:

在迂腐的层面上,你“阻止”Application.ProcessMessages 的方式是不调用任何代码

  1. 显示模式对话框
  2. 调用 SendMessage
  3. 运行自己的本地消息循环
  4. 调用 Application.ProcessMessages(这是一个本地消息循环)

如果您编写的循环只执行数值计算和文件 I/O,则您的 UI 将被冻结,直到您退出循环,因为没有处理任何消息。

如果您希望您的 UI 在未知任意代码(第三方库)的某些长时间运行的操作期间具有响应性,但您不希望在此期间在您的应用中发生某些类型的操作,这是一个不同的问题 -那是关于防止重入。您希望防止在进行特定活动时使用您的代码的某些部分。例如,模式对话框通过禁用除模式对话框本身之外的所有应用程序的顶级窗口来阻止您与对话框下方的应用程序窗口进行交互。

【讨论】:

    猜你喜欢
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 2013-05-25
    • 1970-01-01
    • 2015-08-27
    相关资源
    最近更新 更多