WTL CIdleHandler 的正确用法是什么?
What is the proper use of WTL CIdleHandler?
我正在尝试学习 WTL/Win32 编程,我不太了解 CIdleHandler mixin 的设计class。
对于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(用户在 Window 上左键单击了某些东西)会 激活 空闲处理(bDoIdle = True),但是 WM_MOUSEMOVE 被显式调用以防止重新激活空闲处理。
谁能给我"proper" WTL Idle Loops(或更具体地说:CIdleHandler)的使用场景?我想我的期望是空闲处理功能将是小的增量任务,只需说... 100 毫秒即可完成。然后他们会在后台重复调用。
但是WTL好像不是这样的。或者我可能没有完全理解空闲循环?因为如果我有一个注册为 CIdleHandler 的增量后台任务...那么如果用户离开 window,任务将只获得一次 运行!如果没有任何消息注入系统(例如 WM_LBUTTONDOWN),bDoIdle 变量将一直保持为假!
有人对这一切有好的解释吗?
如评论中所述,OnIdle
处理程序应该在某些 activity 后空转开始时被调用,尤其是。为了更新 UI。这解释了 "once" 处理程序的调用:发生了一些事情,然后你有机会更新 UI 元素。如果您需要持续的后台处理,您应该使用计时器或工作线程。
WTL 示例建议使用空闲处理程序,例如在 \Samples\Alpha\mainfrm.h.
Window class 获取线程的消息循环并请求空闲更新:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
稍后在消息处理和用户交互之后,空闲处理程序更新工具栏以反映可能的状态更改:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
我正在尝试学习 WTL/Win32 编程,我不太了解 CIdleHandler mixin 的设计class。
对于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(用户在 Window 上左键单击了某些东西)会 激活 空闲处理(bDoIdle = True),但是 WM_MOUSEMOVE 被显式调用以防止重新激活空闲处理。
谁能给我"proper" WTL Idle Loops(或更具体地说:CIdleHandler)的使用场景?我想我的期望是空闲处理功能将是小的增量任务,只需说... 100 毫秒即可完成。然后他们会在后台重复调用。
但是WTL好像不是这样的。或者我可能没有完全理解空闲循环?因为如果我有一个注册为 CIdleHandler 的增量后台任务...那么如果用户离开 window,任务将只获得一次 运行!如果没有任何消息注入系统(例如 WM_LBUTTONDOWN),bDoIdle 变量将一直保持为假!
有人对这一切有好的解释吗?
如评论中所述,OnIdle
处理程序应该在某些 activity 后空转开始时被调用,尤其是。为了更新 UI。这解释了 "once" 处理程序的调用:发生了一些事情,然后你有机会更新 UI 元素。如果您需要持续的后台处理,您应该使用计时器或工作线程。
WTL 示例建议使用空闲处理程序,例如在 \Samples\Alpha\mainfrm.h.
Window class 获取线程的消息循环并请求空闲更新:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
稍后在消息处理和用户交互之后,空闲处理程序更新工具栏以反映可能的状态更改:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}