C++ WTL CIdleHandler的正确用法是什么?

C++ WTL CIdleHandler的正确用法是什么?,c++,windows,winapi,atl,wtl,C++,Windows,Winapi,Atl,Wtl,我试图学习WTL/Win32编程,但我不太了解CIdleHandler mixin类的设计 对于WTL9.1,CMessageLoop代码如下(来自atlapp.h): 对空闲处理程序的实际调用非常简单 // override to change idle processing virtual BOOL OnIdle(int /*nIdleCount*/) { for(int i = 0; i < m_aIdleHandler.GetSize(); i++) {

我试图学习WTL/Win32编程,但我不太了解CIdleHandler mixin类的设计

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

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

// 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
}

我的分析如下:似乎每个“PeekMessage Drain”(没有消息发送到Win32应用程序的一段时间)调用一次OnIdle处理程序

但为什么只有一次?您不希望在查看消息时,后台空闲任务不断地被反复调用吗?此外,我觉得奇怪的是,WM_LBUTTONDOWN(用户左键单击窗口上的某个内容)将激活空闲处理(bDoIdle=True),但WM_MOUSEMOVE被显式调用以防止重新激活空闲处理

有谁能告诉我WTL空闲循环的“正确”使用场景(或者更具体地说:CIdleHandler)?我想我的期望是空闲的处理函数将是小的、增量的任务,只需要说。。。100毫秒完成。然后他们会在后台被反复调用

但似乎WTL的情况并非如此。或者我没有完全理解空闲循环?因为如果我有一个增量后台任务注册为CIdleHandler。。。然后,如果用户离开窗口,任务将只运行一次!如果没有任何消息注入系统(例如WM_LBUTTONDOWN),bDoIdle变量将始终保持为false


有人对此有很好的解释吗?

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

WTL示例建议使用空闲处理程序,例如在

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

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;
}

空闲处理程序仅针对更新ui状态进行设计。比如说工具栏上的启用/禁用按钮,如果活动文档被更改,我不太可能解释为什么在什么都没有发生的情况下应该运行代码,但是,这个解释(以及其他注释)很有意义。关于怠速的MFC文档与您相矛盾:,但我相信您的建议胜过本例中的文档。创建新线程/利用计时器进行“冗长的后台处理”更有意义。
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;
}