图像闪烁原因分析
闪烁的原因是在快速频繁的 调整图像的显示内容时,总是要有一个操作便是刷新背景再填充图像,快速切换图像过程中背景与图像的强烈反差导致了闪烁的问题。
闪烁解决方案
-
不刷背景
不刷新背景,只刷新前景图片可以有效的解决图像闪烁问题,但是随之而来的如果图像没有完整的覆盖目标区域,未覆盖区域将无法更新去除下层显示的数据,如果不涉及为完全覆盖问题 避免刷新背景是最佳的实现方案
手动通知刷新时InvalidateRect(CRect(0,0,cx,cy), 0); 第一个参数是刷新范围,第二个参数写0便可以避免更新背景。
-
避免直接在显示屏DC刷背景
其实闪烁的最直接原因就是DC绘制到屏幕上的速度太慢,而且还分背景和前景 分别绘制两次 这导致了存在大量时间的窗口空白期,因此无论你电脑性能多高,多次刷新屏幕显示总能看到闪烁,那么知道时间消耗的地方后,便有另一种方式去减少时间的消消耗和时间的占用,便是减少直接向显示屏的绘制次数 和修改时间。
使用新增DC管理类CMemDC,对屏幕OnDraw(CDC* pDC)的pDC指针进行管理,使用后 绘制操作没有变换,并且其创建一个等大的内存DC作为缓存区,在CMemDC析构的时候把缓存数据一次性的写入到屏幕显示区中。
代码演示如下:
代码说明,因为CMemDC 在”析构的时候才把缓存区数据写入屏幕“这一特性,CMemDC不能长期存在于成员变量,具体其他实现方案自行开发,这里仅作演示。
我先获取客户区大小,在内存中填充背景颜色(FillRect),再在内存中绘制目标图像m_CDC,这几个操作均在内存中消耗时间仅在10ms以内, 此函数退出后,调用CMemDC的析构函数,图像一次性绘制到显示区域
提示,OnDraw中不宜做过多运算,虽然先写入内存DC能极大的提高速度,但是如果此处的运算量过多仍然出现显示卡顿的问题,所以这里建议,尽可能的分开运算。
有人建议直接关闭背景的绘制操作,我这里建议不要这么做
void CMFCView::OnDraw(CDC* pDC)
{
CMFCDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CMemDC memDC(*pDC,this);
pDC = &memDC.GetDC();
// TODO: 在此处为本机数据添加绘制代码
CRect rect;
GetClientRect(&rect);
COLORREF colorVal = RGB(50, 50, 50);
//pDC->FloodFill(0,0,colorVal);
pDC->FillRect(rect,&CBrush(colorVal));
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_CDC, 0, 0, SRCCOPY);
}
关于CMemDC 类定义
在VS内置库 Path:..\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\include\afxcontrolbarutil.h
class CMemDC
{
public:
AFX_IMPORT_DATA static BOOL m_bUseMemoryDC;
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; }
protected:
CDC& m_dc;
BOOL m_bMemDC;
HANDLE m_hBufferedPaint;
CDC m_dcMem;
CBitmap m_bmp;
CBitmap* m_pOldBmp;
CRect m_rect;
};