我正在学习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; }