MDI 应用程序中的闪烁问题






3.10/5 (13投票s)
2005年8月3日
1分钟阅读

181807

1423
提供了一个解决MDI应用程序中闪烁问题的方案。

Issue
本文说明了如何在MDI应用程序中修复一个常见的闪烁问题,当您创建或激活一个MDI子窗口并且应用程序处于最大化状态时,会出现此问题。 您会瞥见上面图片中显示的新激活的MDI子窗口。
重现问题的方法
- 创建一个新的MFC MDI应用程序项目。
- 运行并最大化应用程序。
- 在最大化状态下,创建几个MDI子窗口并尝试在它们之间切换。
当您创建新窗口或激活非活动窗口时,您会看到闪烁。
解决方法
解决这个问题的方法非常简单。 闪烁来自于绘制恢复的MDI子窗口的标题栏、边框和客户端区域。 为了消除它,请在从CMDIChildWnd派生的类中重写“WindowProc”。 对于非客户端区域,过滤WM_NCPAINT消息,对于客户端区域,像这样处理WM_SIZE消息
if(message==WM_SIZE) // client area { if(wParam==SIZE_MAXIMIZED && pChildFrame==this) // active and maximized return CMDIChildWnd::WindowProc(message, wParam, lParam); SetRedraw(FALSE); // disable drawing LRESULT ret = CMDIChildWnd::WindowProc(message, wParam, lParam); // default Window procedure SetRedraw(); // enable drawing return ret; }
在本文的早期版本中,我还过滤了消息174。 忽略此消息会阻止绘制非主题化的标题按钮。 按钮的图片如下所示

当窗口恢复时也会发送此消息。 现在恢复窗口的绘制已被禁用,因此不再需要在“if”语句中包含“message==174”了。
我还将if(message==WM_NCPAINT || message==WM_SIZE)作为窗口过程的第一行添加了进去。 这可以防止在objcore.cpp (AfxAssertValidObject) 中出现断言,当您尝试关闭MDI子窗口,视图是从CHtmlView派生的,并且活动配置是“Debug”时。
因此,解决方法代码如下所示
LRESULT CChildFrame::WindowProc(UINT message, 
                       WPARAM wParam, LPARAM lParam) 
{
    if(message==WM_NCPAINT || message==WM_SIZE)
    {
        BOOL bMax;
        CMDIFrameWnd* pParentFrame = (CMDIFrameWnd*)GetParentFrame();
        if(pParentFrame)
        {
            CMDIChildWnd* pChildFrame = pParentFrame->MDIGetActive(&bMax);
            if(bMax)
            {    
                if(message==WM_NCPAINT) // non client area
                    return 0;
                    
                if(message==WM_SIZE) // client area
                {
                    if(wParam==SIZE_MAXIMIZED && 
                       pChildFrame==this) // active and maximized
                      return CMDIChildWnd::WindowProc(message, wParam, lParam);
                    SetRedraw(FALSE);
                    LRESULT ret = 
                      CMDIChildWnd::WindowProc(message, wParam, lParam);
                    SetRedraw();
                    return  ret;
                }
            }
        }
    }
    return CMDIChildWnd::WindowProc(message, wParam, lParam);
}
一个演示应用程序
选中/取消选中“FIX”按钮以启用/禁用修复代码。
