如何停止窗口渲染并稍后恢复?

时间:2009-10-11 13:56:54

标签: user-interface winapi mmc doublebuffered

我想阻止我的窗口更新,直到我从服务器接收数据并呈现它。我可以挂钩WM_PAINT事件,或者更好的是仍然调用一些Win32API方法来防止窗口被更新并在以后解冻它?

更多信息: 在用C#编写的MMC管理单元的上下文中,我们的应用程序遭受恼人的闪烁和双重排序行为: 我们使用MMC的listViews,但是因为我们订阅了sort事件。 MMC做了它自己的魔术并对正在显示的页面进行排序(我们无法覆盖它),当我们从服务器收到回复时,我们再次更改listView。 每行更改按顺序完成,没有beginUpdate等。(AFAIK)。

3 个答案:

答案 0 :(得分:1)

通常情况下挂钩WM_PAINT是可行的方法,但请确保您也忽略所有WM_ERASEBKGND通知,否则您仍然会闪烁,因为Windows会为您删除Windows区域。 (返回非零以防止Windows执行此操作)

另一种可能性是使用LockWindowUpdate函数,但它有一些缺点:

  • 只能锁定一个窗口
  • 解锁后整个桌面和所有子窗口(即所有内容)都重新绘制,导致整个桌面的短暂闪烁。 (在XP上比在Vista上更糟糕)

答案 1 :(得分:1)

有些控件有BeginUpdateEndUpdate API用于此目的。

如果您执行了某些操作(例如,挂钩和忽略绘制事件),请禁用绘画,那么稍后强制重新绘制的方法是调用Invalidate方法。

答案 2 :(得分:0)

好的,在所有搜索和检查之后我发现LockUpdateWindow是个坏主意 - 例如参见Raimond Chen OldNewThing的文章。但即使实现SetRedrawWindow的想法也不是那么简单 - 因为我所拥有的只是从主窗口的IConsole2 * pConsole-> GetMainWindow()HWND处理程序中获得的。通过将其设置为SetRedraw = FALSE,它以非常奇怪的方式消失了。虽然为了使程序只运行TreeView而不是整个应用程序(我们的左侧面板),我运行

EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw

其中SetChildRedraw回调是以下一种方式定义的:

#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam) 
{ 
    RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
    DECLARE_STRING(sText)
    GetClassName(hwndChild, sText, MAX_PATH);
    if (wcsstr(sText, L"SysTreeView32") != NULL)
    {
        SetWindowRedraw(hwndChild, lParam);
        if (lParam == TRUE)
        {
            GetWindowRect(hwndChild, &rcChildRect);
            InvalidateRect(hwndChild, &rcChildRect, TRUE);
        }
    }
    return TRUE;
}