3

考虑一个用 C++ 编写的带有 listview 控件(在报告模式下)的普通 Win32 对话框。在某个事件中,所有项目和所有列都将被删除,并创建新的列和项目。基本上,随着内容的变化,列会根据内容自动生成。

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

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

父对话框已WS_CLIPCHILDREN设置。

有什么建议可以使这项工作尽可能少地闪烁吗?我正在考虑使用两个列表视图,交替可见性,使用隐藏的作为后台缓冲区,但这听起来有点矫枉过正。必须有一个简单的方法。

4

2 回答 2

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

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

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

BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

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

这应该工作得很好。

于 2010-06-30T14:33:48.287 回答
1

在尝试了很多事情和最重要humbagumba的建议之后,我得出了一个非常简单的结论。LockWindowUpdate在这种情况下是每个人的朋友。我不知道为什么它第一次对我不起作用,但是在自定义绘画在所有情况下都无法交付之后,我LockWindowUpdate再次尝试并且它起作用了!

基本上,只需将 listview 上的所有工作都包含在 a 中LockWindowUpdate(hWnd)LockWindowUpdate(NULL)并且一切都很好。甚至没有滚动条闪烁了。

请确保不要嵌套LockWindowUpdate,因为一次只能锁定一个窗口。

于 2010-06-30T16:10:07.197 回答