删除并重新添加所有项目和所有列时,Listview在Win32对话框上闪烁

wpf*_*abe 3 c++ winapi mfc listview listctrl

考虑一个简单的Win32对话框,其中包含用C++编写的listview控件(在报表模式下).在某个事件中,将删除所有项目和所有列,并创建新的列和项目.基本上,随着内容的更改,将根据内容自动生成列.

删除旧项目/列并添加新项目时,listview会像地狱一样闪烁.我尝试过WM_SETREDRAW并且LockWindowUpdate()没有改变视觉体验.

我甚至设置了扩展列表视图样式LVS_EX_DOUBLEBUFFER,这根本没有帮助.

父对话框已WS_CLIPCHILDREN设置.

有关如何使用尽可能少的闪烁工作的任何建议吗?我正在考虑使用两个列表视图,交替可见性,使用隐藏的一个作为后台缓冲区,但这听起来像是一种矫枉过正.必须有一个简单的方法.

hum*_*mba 7

默认的列表控件绘画是非常有缺陷的.但是有一个简单的技巧来实现你自己的双缓冲技术:

CMyListCtrl::OnPaint()
{
    CRect rcClient;
    GetClientRect(rcClient);

    CPaintDC dc(this);
    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);

    CBitmap bmMem;
    bmMem.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
    CBitmap* pbmOld = dcMem.SelectObject(&bmMem);

    dcMem.FillSolidRect(rcClient, ::GetSysColor(COLOR_WINDOW));

    this->DefWindowProc(WM_PAINT, (WPARAM)dcMem.m_hDC, (LPARAM)0);

    dc.BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);
    dcMem.SelectObject(pbmOld);

    CHeaderCtrl*    pCtrl = this->GetHeaderCtrl();
    if (::IsWindow(pCtrl->GetSafeHWnd())
    {
        CRect   aHeaderRect;
        pCtrl->GetClientRect(&aHeaderRect);
        pCtrl->RedrawWindow(&aHeaderRect);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将创建一个位图,然后调用默认窗口过程将列表控件绘制到位图中,然后将位图的内容blitting到paint DC中.

您还应该为WM_ERASEBKGND添加一个处理程序:

BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}
Run Code Online (Sandbox Code Playgroud)

这将阻止控件在重绘之前始终擦除背景.如果为位图添加成员变量,并且仅在窗口大小发生变化时(重新)创建它,则可以进一步优化OnPaint(因为根据窗口的大小,始终创建位图的成本可能很高).

这应该工作得很好.