圖像閃爍原因分析
閃爍的原因是在快速頻繁的 調整圖像的顯示內容時,總是要有一個操作便是刷新背景再填充圖像,快速切換圖像過程中背景與圖像的強烈反差導致了閃爍的問題。
閃爍解決方案
-
不刷背景
不刷新背景,只刷新前景圖片可以有效的解決圖像閃爍問題,但是隨之而來的如果圖像沒有完整的覆蓋目標區域,未覆蓋區域將無法更新去除下層顯示的數據,如果不涉及爲完全覆蓋問題 避免刷新背景是最佳的實現方案
手動通知刷新時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;
};