间隔设置为1秒的TTimer每1秒发送一条消息。在应用程序的消息循环中处理此消息,这导致触发OnTimer事件。
如果应用程序很忙,没有时间处理消息循环,则将跳过OnTimer事件。
我知道TTimer内部使用SetTimer。
我的问题是:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Caption = i;
i++;
MessageDlg(stuff); <----- we "block" application here but form's caption is still updated.
}
答案 0 :(得分:5)
如果应用程序繁忙且没有时间处理消息循环,则将跳过OnTimer事件。
这是正确的。 MSDN上的This和this博客文章提供了一些内部实现细节,特别是它们提到到期计时器导致设置了消息队列状态的QS_TIMER
标志。没有更多的时间流逝将导致队列状态标志被进一步设置。设置此标志且[Peek|Get]Message
无法选择任何更高优先级的消息时,将生成计时器消息。
尽管计时器消息没有堆积在队列中,但是在执行先前的事件处理程序时,有可能再次触发计时器。当处理程序中的代码执行时间超过计时器间隔并允许重新输入时,这是可能的。如果计时器处理程序导致应用程序处理排队的消息,则可能会清除任何待处理的队列状态标志并再次发布消息,这可能会导致计时器在处理程序完成执行之前触发。
TTimer是否使用内部/独立线程(通过SetTimer)?
不。在主线程中创建了一个实用程序窗口,它将接收计时器消息。收到计时器消息后,如果分配了此窗口,则此窗口将调用事件处理程序。
保存计时器的表单(甚至包括它的OnTimer)为何如此 模态MessageDlg正在“阻止”表单,仍然可以做些什么?
模态循环继续处理队列,它在调用HandleMessage
的循环中调用应用程序的ProcessMessage
。因此,计时器消息仍在处理。
这是上述再次进入的潜在原因。您可以使用标志或禁用/启用计时器来防止这种情况。或者将处理程序中的所有消息处理都排除在外。
文档说SetTimer至少需要Win2000。 TTimer是如何在Win98中实现的
相同。文档不断变化,有时MSDN会从最低要求中删除不受支持的OS版本-不一致。我的XE2 API文档指出:
最低操作系统 Windows 95,Windows NT 3.1
用于WM_TIMER
消息。
答案 1 :(得分:4)
WM_TIMER消息永远不会放在消息队列中。它们在队列为空并且设置了指示计时器已过期的标志时生成。因此,队列中一次不会出现多个WM_TIMER消息,并且如果您的应用程序太忙而无法处理队列,则不会有很多WM_TIMER消息等待处理。
WM_PAINT消息的工作方式相同。