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