windows 如何防止在 CListCtrl 上闪烁?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2486682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I prevent flickering on CListCtrl?
提问by sorin
I'm using a CListCtrl/CListView report view (LVS_REPORT
) in virtual mode (LVS_OWNERDATA
) with LVS_EX_DOUBLEBUFFER
enabled and I encounter ugly flickering. Double buffer have a real effect but it doesn't stop all flickering (without it very slow).
我LVS_REPORT
在虚拟模式 ( LVS_OWNERDATA
)下使用 CListCtrl/CListView 报告视图( ) 并LVS_EX_DOUBLEBUFFER
启用,但我遇到了难看的闪烁。双缓冲有一个真正的效果,但它不会停止所有的闪烁(没有它很慢)。
I'm not looking for switching to other controls that would require a high amount of rework (like ObjectListView)
我不是在寻找切换到需要大量返工的其他控件(如 ObjectListView)
How does the flickering behaves:
闪烁的表现如何:
- on column resize - the background is first clean using lightgray and after this is displayed the text (background is white)
- on mouse scroll (animated) - for a very short time there is lightgray-bar displayed in the area where new lines are to be displayed.
- 调整列大小 - 首先使用浅灰色清洁背景,然后显示文本(背景为白色)
- 鼠标滚动(动画) - 在很短的时间内,在要显示新行的区域中会显示浅灰色条。
It looks like it does clean the background using the default window background color (lightgray) for the area where it has to redraw.
看起来它确实使用默认窗口背景颜色(浅灰色)清洁了必须重绘的区域的背景。
How do I solve the flickering problem?
如何解决闪烁问题?
回答by VitalyVal
Try to do the following: - Set Clip Children and Clip Sibling for paremt dialog of List Control. - Make dirived from CListCtrl class. In this class overwrite OnEraseBkgnd. In the OnEraseBkgnd fill with background color area around of visible items of the list. The OnEraseBkgnd can look like:
尝试执行以下操作: - 为 List Control 的 paremt 对话框设置 Clip Children 和 Clip Sibling。- 从 CListCtrl 类制作。在这个类中覆盖 OnEraseBkgnd。在 OnEraseBkgnd 中填充列表可见项目周围的背景颜色区域。OnEraseBkgnd 看起来像:
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;
}
回答by nbozovic
I know only way to have flicker free is using double buffering or MemDC.
我知道无闪烁的唯一方法是使用双缓冲或 MemDC。
have found this article: Flicker-free-drawing-of-any-control
找到了这篇文章:Flicker-free-drawing-of-any-control
This article explains it well how to quickly perform Non Flickering drawing on your CListCtrl. And it works excellent.
这篇文章很好地解释了如何在你的 CListCtrl 上快速执行非闪烁绘图。而且效果很好。
PS: VS 2005 doesn't have CMemDC class you will need to implement it your self, or use the following code:
PS:VS 2005 没有 CMemDC 类,您需要自己实现它,或者使用以下代码:
//
// 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));
}