【MFC】使用CMemDC解決圖像顯示閃爍問題

圖像閃爍原因分析

閃爍的原因是在快速頻繁的 調整圖像的顯示內容時,總是要有一個操作便是刷新背景再填充圖像,快速切換圖像過程中背景與圖像的強烈反差導致了閃爍的問題。

閃爍解決方案

  1. 不刷背景

    不刷新背景,只刷新前景圖片可以有效的解決圖像閃爍問題,但是隨之而來的如果圖像沒有完整的覆蓋目標區域,未覆蓋區域將無法更新去除下層顯示的數據,如果不涉及爲完全覆蓋問題 避免刷新背景是最佳的實現方案 

    手動通知刷新時InvalidateRect(CRect(0,0,cx,cy), 0); 第一個參數是刷新範圍,第二個參數寫0便可以避免更新背景。

  2. 避免直接在顯示屏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;
};

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章