如何使用MFC在CWinApp中接收计时器事件?

时间:2008-10-17 17:43:02

标签: winapi mfc

在MFC中我试图设置一个空处理程序计时器(即没有窗口)。但是我无法在CWinApp MESSAGE_MAP中处理WM_TIMER事件。这可能吗?如果是这样,怎么样?

3 个答案:

答案 0 :(得分:13)

正如MSDN所述,SetTimer()有两种操作模式:一种将定时器与一个窗口相关联,另一种将定时器与线程的消息队列相关联。当你有一个窗口,你可以使用前者;否则,你必须使用后者。并且CWinApp 不是窗口。

在线程队列中捕获计时器消息

UINT_PTR uTimerId = SetTimer(NULL, 0, 2000, NULL);
TRACE(_T("Timer created - ID=%x\n"), uTimerId);

这将创建一个新的计时器,设置为每两秒触发一次,仅与当前线程的消息队列相关联。如果不将其与窗口关联,则无法指定计时器ID,因此请保存在类成员或其他内容中返回的ID - you'll have a rough time killing the timer later on if you forget。然后,您可以在CWinApp::PreTranslateMessage()覆盖中处理此问题:

BOOL CMyFunkyApp::PreTranslateMessage(MSG* pMsg)
{
   if (pMsg->message == WM_TIMER)
   {
      TRACE(_T("Timer fired - ID=%x\n"), pMsg->wParam);
   }

   return CWinApp::PreTranslateMessage(pMsg);
}

请注意,像这样挂入线程的消息循环是 only 方式来处理这样设置的定时器 - 正如我们所讨论的那样,没有窗口,虽然MFC确实提供了消息映射工具对于CWinApp,您无法使用ON_WM_*()宏,因为......好吧,因为它不是一个窗口。但是,还有另一种略微不那么混乱的方式:回调。

使用回调处理计时器消息

void CALLBACK TimerCallback(HWND, UINT, UINT_PTR id, DWORD dwTime)
{
   TRACE(_T("Timer fired - ID=%x\n"), id);
}

//...

UINT_PTR uTimerId = SetTimer(NULL, 0, 2000, &TimerCallback);
TRACE(_T("Timer created - ID=%x\n"), uTimerId);

这与完全与第一个例子完全相同:新的计时器配置为每两秒触发一次,与当前线程的消息队列相关联......但是 this one有一个与之关联的回调地址。并且默认消息处理程序知道在处理这样的定时器消息时调用回调,因此您不必费心连接到消息循环。

所以你去吧。两种使用CWinApp计时器的方法。

答案 1 :(得分:2)

我通过制作一个不可见的窗口并在其上设置计时器来完成此操作。

答案 2 :(得分:2)

查看Raymond Chen的这篇文章。有一些有趣的小块可以帮助你解决问题。

Why your thread is spending all its time processing meaningless thread timers