首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何防止CListCtrl上的闪烁?

如何防止CListCtrl上的闪烁?
EN

Stack Overflow用户
提问于 2010-03-21 10:23:20
回答 3查看 7.8K关注 0票数 3

我在虚拟模式(LVS_OWNERDATA)中使用CListCtrl/CListView报表视图(LVS_OWNERDATA),启用了LVS_EX_DOUBLEBUFFER,遇到了难看的闪烁。双缓冲区有一个真正的效果,但它不能阻止所有的闪烁(没有它非常慢)。

我不想切换到其他需要大量返工的控件(比如ObjectListView)。

闪烁是如何表现的:

  • 在调整列大小时,首先使用轻灰色清除背景,然后显示文本(背景为白色)。
  • 在鼠标滚动(动画)-在很短的时间内,有亮灰色条显示在新的线条要显示的区域。

它看起来确实清洁了背景使用默认窗口背景颜色(轻灰色)的区域,它必须重新绘制。

我如何解决闪烁的问题?

EN

回答 3

Stack Overflow用户

发布于 2010-03-21 10:49:02

尝试执行以下操作:-为列表控件的paremt对话框设置“剪辑孩子”和“剪辑兄弟”。-从CListCtrl类中分离出来。在这个类中覆盖OnEraseBkgnd。在OnEraseBkgnd中,在列表中的可见项周围填充背景色区域。OnEraseBkgnd可以看起来像:

代码语言:javascript
运行
复制
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC) 
{
    CBrush  br;
    CRect   rcCli;
    CRect   rcItemsRect(0, 0, 0, 0);
    int     nHeadHeight = 0;
    int     nItems      = GetItemCount();

    GetClientRect(&rcCli);

    CHeaderCtrl* pHeadCtrl = GetHeaderCtrl();
    if (pHeadCtrl)
    {
        CRect  rcHead;
        pHeadCtrl->GetWindowRect(&rcHead);
        nHeadHeight = rcHead.Height();
    }
    rcCli.top += nHeadHeight;

    if (nItems > 0)
    {
        CPoint  ptItem;
        CRect   rcItem;

        GetItemRect(nItems - 1, &rcItem, LVIR_BOUNDS);
        GetItemPosition(nItems - 1, &ptItem);

        rcItemsRect.top    = rcCli.top;
        rcItemsRect.left   = ptItem.x;
        rcItemsRect.right  = rcItem.right;
        rcItemsRect.bottom = rcItem.bottom;

        if (GetExtendedStyle() & LVS_EX_CHECKBOXES)
            rcItemsRect.left -= GetSystemMetrics(SM_CXEDGE) + 16;
    }

    br.CreateSolidBrush(GetBkColor());

    if (rcItemsRect.IsRectEmpty())
        pDC->FillRect(rcCli, &br);
    else
    {
        if (rcItemsRect.left > rcCli.left)     // fill left rectangle
            pDC->FillRect(
                CRect(0, rcCli.top, rcItemsRect.left, rcCli.bottom), &br);
        if (rcItemsRect.bottom < rcCli.bottom) // fill bottom rectangle
            pDC->FillRect(
                CRect(0, rcItemsRect.bottom, rcCli.right, rcCli.bottom), &br);
        if (rcItemsRect.right < rcCli.right) // fill right rectangle
            pDC->FillRect(
                CRect(rcItemsRect.right, rcCli.top, rcCli.right, rcCli.bottom), &br);
    }

    return TRUE;
}
票数 3
EN

Stack Overflow用户

发布于 2012-11-05 15:57:56

我知道只有使用双缓冲或MemDC才能使闪烁自由。

找到本文:任何控制的无闪烁绘图

本文很好地解释了如何在CListCtrl上快速执行非闪烁绘图。而且效果很好。

PS: VS 2005没有CMemDC类,您需要实现它,或者使用以下代码:

代码语言:javascript
运行
复制
//
// CMemDC.h header file
//
#pragma once

class CMemDC
{
public:
    CMemDC(CDC& dc, CWnd* pWnd);
    CMemDC(CDC& dc, const CRect& rect);

    virtual ~CMemDC();

    CDC& GetDC() { return m_bMemDC ? m_dcMem : m_dc; }
    BOOL IsMemDC() const { return m_bMemDC; }
    BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }

  void EraseBkClip();
protected:
    CDC&     m_dc;
    BOOL     m_bMemDC;
    HANDLE   m_hBufferedPaint;
    CDC      m_dcMem;
    CBitmap  m_bmp;
    CBitmap* m_pOldBmp;
    CRect    m_rect;
};

//
// CMemDC.cpp source file
//
#include "CMemDC.h"

CMemDC::CMemDC(CDC& dc, CWnd* pWnd) :
    m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL)
{
    ASSERT_VALID(pWnd);

    pWnd->GetClientRect(m_rect);
    m_rect.right += pWnd->GetScrollPos(SB_HORZ);
    m_rect.bottom += pWnd->GetScrollPos(SB_VERT);   
    if (m_dcMem.CreateCompatibleDC(&m_dc) && 
      m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
    {
        m_bMemDC = TRUE;
        m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
    }
}

CMemDC::CMemDC(CDC& dc, const CRect& rect) :
    m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL), m_rect(rect)
{
    ASSERT(!m_rect.IsRectEmpty());
    if (m_dcMem.CreateCompatibleDC(&m_dc) &&
      m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
    {
        m_bMemDC = TRUE;
        m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
    }
}

CMemDC::~CMemDC()
{
    if (m_bMemDC)
    {
        CRect rectClip;
        int nClipType = m_dc.GetClipBox(rectClip);

        if (nClipType != NULLREGION)
        {
            if (nClipType != SIMPLEREGION)
            {
                rectClip = m_rect;
            }
            m_dc.BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), &m_dcMem, rectClip.left, rectClip.top, SRCCOPY);
        }

        m_dcMem.SelectObject(m_pOldBmp);
    }
}

void CMemDC::EraseBkClip()
{
  CRect clip;
  m_dcMem.GetClipBox(&clip);
  m_dcMem.FillSolidRect(clip, GetSysColor(COLOR_WINDOW));
}
票数 2
EN

Stack Overflow用户

发布于 2021-11-23 01:49:42

我发现有一种非常简单的方法对我有效:

  1. m_List1.SetRedraw(false)关闭重绘
  2. m_List1.ResetContents()重置内容
  3. 使用m_List1.AddString()在循环中添加新字符串
  4. 然后通过打开重绘和一个m_List1.UpdateWindow()来完成。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2486682

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档