什么是WTL CIdleHandler的正确使用?

我正在学习WTL / Win32编程,而且我不太了解CIdleHandler mixin类的devise。

对于WTL 9.1,CMessageLoop代码如下(来自atlapp.h):

for(;;) { while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE)) { if(!OnIdle(nIdleCount++)) bDoIdle = FALSE; } bRet = ::GetMessage(&m_msg, NULL, 0, 0); if(bRet == -1) { ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n")); continue; // error, don't process } else if(!bRet) { ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n")); break; // WM_QUIT, exit message loop } if(!PreTranslateMessage(&m_msg)) { ::TranslateMessage(&m_msg); ::DispatchMessage(&m_msg); } if(IsIdleMessage(&m_msg)) { bDoIdle = TRUE; nIdleCount = 0; } } 

对闲置处理程序的实际调用非常简单。

 // override to change idle processing virtual BOOL OnIdle(int /*nIdleCount*/) { for(int i = 0; i < m_aIdleHandler.GetSize(); i++) { CIdleHandler* pIdleHandler = m_aIdleHandler[i]; if(pIdleHandler != NULL) pIdleHandler->OnIdle(); } return FALSE; // don't continue } 

就像对IsIdleMessage的调用一样

 static BOOL IsIdleMessage(MSG* pMsg) { // These messages should NOT cause idle processing switch(pMsg->message) { case WM_MOUSEMOVE: #ifndef _WIN32_WCE case WM_NCMOUSEMOVE: #endif // !_WIN32_WCE case WM_PAINT: case 0x0118: // WM_SYSTIMER (caret blink) return FALSE; } return TRUE; } 

我的分析如下:对于每个“PeekMessage Drought”(一段时间没有消息发送到Win32应用程序),看起来就像一次 ,OnIdle处理程序被调用。

但为什么只是一次? 在PeekMessage的情况下,你不希望背景闲置任务不断地被重复地调用吗? 而且,WM_LBUTTONDOWN(用户已经在窗口上左键点击了某些东西)会激活空闲处理(bDoIdle = True),但是WM_MOUSEMOVE被明确地调用以防止重新激活空闲处理,这似乎很奇怪。

任何人都可以给我WTL空闲循环(或更具体的:CIdleHandler)的“适当的”使用场景? 我想我的期望是,空闲处理function将是小的,增量式的任务,只需要说… 100毫秒完成。 然后他们会在后台被反复调用。

但WTL似乎并非如此。 或者,也许我不完全理解空闲循环? 因为如果我有一个增量后台任务注册为CIdleHandler …那么如果用户离开窗口,任务将只能运行一次! 如果没有任何消息被input到系统(比如WM_LBUTTONDOWN),bDoIdlevariables将一直保持为false!

有没有人对这一切有一个很好的解释?

正如在评论中所说的, OnIdle处理程序应该在某些活动后空闲开始时被调用, 为了更新UI。 这解释了“曾经”调用处理程序:发生了一些事情,然后您有机会一次更新UI元素。 如果您需要进行后台处理,则应该使用定时器或工作线程。

WTL示例建议使用空闲的处理程序,例如\ Samples \ Alpha \ mainfrm.h中 。

窗口类拾取线程的消息循环并请求空闲更新:

 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // ... // register object for message filtering and idle updates CMessageLoop* pLoop = _modulee.GetMessageLoop(); ATLASSERT(pLoop != NULL); pLoop->AddMessageFilter(this); pLoop->AddIdleHandler(this); 

稍后在消息处理和用户交互之后,空闲处理程序更新工具栏以反映可能的状态更改:

 virtual BOOL OnIdle() { UIUpdateToolBar(); return FALSE; }