最近在寫一個圖像編輯軟件,,環(huán)境是MFC,,但是MFC的視圖刷新機制使得圖像閃爍得非常厲害(圖像縮放時尤其明顯),,在網上查了一些資料,最好的方法是用雙緩沖的方式顯示,,這里總結一下,。
雙緩沖的原理可以這樣形象的理解:把電腦屏幕看作一塊黑板。首先我們在內存環(huán)境中建立一個“虛擬“的黑板,,然后在這塊黑板上繪制復雜的圖形,,等圖形全部繪制完畢的時候,再一次性的把內存中繪制好的圖形“拷貝”到另一塊黑板(屏幕)上,。采取這種方法可以提高繪圖速度,,極大的改善繪圖效果。
主要實現(xiàn)代碼如下:
1 CDC MemDC; //首先定義一個內存顯示設備對象 2 CBitmap MemBitmap;//定義一個位圖對象 3 MemDC.CreateCompatibleDC(NULL); //創(chuàng)建兼容設備dc 4 MemBitmap.CreateCompatibleBitmap(pDC,W,H); 5 CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); 6 MemDC.FillSolidRect(0,0,W,H,RGB(255,255,255));//填充初始顏色 7 cimg.DrawToHDC(MemDC.GetSafeHdc(),CRect(0,0,W,H));//繪圖到內存顯示設備 8 9 pDC->BitBlt(rect.left,rect.top,W,H,&MemDC,0,0,SRCCOPY); //繪圖到真實顯示設備
主要思路就是先創(chuàng)建一個虛擬dc和一張?zhí)摂M位圖,,用于將圖像輸出到虛擬設備上,,內容在虛擬設備揮好后再輸出到真實dc上顯示出來,這樣在要輸出的時候才輸出,,提高了繪圖效率,。在這種方式下,所有需要顯示的函數(shù)都可以先會在內存虛擬dc上,,虛擬dc可以作為一個全局的變量或者類的成員變量存在,,方便調用。
另外還需重載背景刷新函數(shù)OnEraseBkgnd(view類的函數(shù)),,其的主要作用是刷新背景,,刷新次數(shù)頻繁了就出現(xiàn)了閃爍,因此在需要的時候調用這個函數(shù),,其他時候直接return ture即可,。
其實基本思路還是暫停MFC自帶的刷新機制,控制圖像的刷新,,在你想要刷新的時候刷新即可,。
另外有個參考資料如下,,不懂實際操作時候可以參考,。
1 內存DC和內存位圖
2 (一)實驗目的: 3 學會使用內存DC解決重畫問題 4 5 (二)實驗內容: 6 7 當Windows系統(tǒng)需要重畫窗口時,會向窗口發(fā)送一條WM_PAINT消息,,應用程序需要在WM_PAINT消息響應函數(shù)(或View類中的OnDraw)中重畫整個窗口(即重新顯示窗口中的信息),。 8 可以把所有繪圖的工作放到OnDraw、OnPaint等函數(shù)中作,,但這樣作可能會出現(xiàn)三個缺點:速度慢,、屏幕閃爍、不方便,。 9 所以,,對于需要較復雜繪圖的程序,一般方法是在內存中保存窗口內容的一個拷貝(內存DC)來實現(xiàn)重畫。每次收到WM_PAINT消息時,,將內存DC的內容復制到屏幕上,。 10 11 1、重建一個工程,,在View類的頭文件中向View類添加成員變量:指向內存DC的指針和指向內存位圖的指針 12 CDC* m_pMemDC; 13 CBitmap* m_pBitmap; 14 2,、在View類的構造函數(shù)中添加代碼創(chuàng)建CDC和CBitmap對象 15 m_pMemDC=new CDC(); 16 m_pBitmap=new CBitmap(); 17 3、在View類的析構函數(shù)中添加代碼銷毀CDC和CBitmap對象 18 delete m_pMemDC; 19 delete m_pBitmap; 20 4,、用Class Wizard為View類添加一個WM_CREATE消息處理函數(shù)OnCreate(LPCREATESTRUCT lpCreateStruct),,在處理函數(shù)中添加代碼創(chuàng)建內存DC和位圖 21 //得到屏幕尺寸 22 int maxX=GetSystemMetrics(SM_CXSCREEN); 23 int maxY=GetSystemMetrics(SM_CYSCREEN); 24 //創(chuàng)建內存DC和位圖 25 CDC* pDC=GetDC(); 26 m_pMemDC->CreateCompatibleDC(pDC); 27 m_pBitmap->CreateCompatibleBitmap(pDC,maxX,maxY); 28 m_pMemDC->SelectObject(m_pBitmap); 29 ReleaseDC(pDC); 30 //初始化內存DC為全白 31 CBrush brush; 32 brush.CreateStockObject(WHITE_BRUSH); 33 CBrush* poldbrush=m_pMemDC->SelectObject(&brush); 34 m_pMemDC->PatBlt(0,0,maxX,maxY,PATCOPY); 35 m_pMemDC->SelectObject(poldbrush); 36 5、在OnDraw中添加重畫代碼 37 CRect rect; 38 GetClientRect(rect); 39 pDC->BitBlt(0,0,rect.Width(),rect.Height(),m_pMemDC,0,0,SRCCOPY); 40 6,、用Class Wizard為View類添加一個WM_LBUTTONDOWN消息處理函數(shù),,用于響應鼠標左鍵單擊消息。 41 7,、在該鼠標消息處理函數(shù)中,,添加繪圖代碼 42 m_pMemDC->TextOut(point.x,point.y,"Test"); 43 Invalidate(FALSE); 44 8、編譯運行程序,,在鼠標左鍵點擊的地方都會顯示出“Test”,。最小化窗口,再恢復窗口,,可以發(fā)現(xiàn)前面顯示的“Test”仍然保留,。 45 46 說明: 47 Invalidate函數(shù)刷新整個窗口,如果每次繪圖修改的區(qū)域較小,,可以使用InvalidateRect函數(shù)代替Invalidate函數(shù)以加快顯示速度,。例如鼠標消息處理函數(shù)中的繪圖代碼可以改為如下代碼: 48 CString str="Test"; 49 CRect rect(point.x,point.y,point.x,point.y); 50 m_pMemDC->DrawText(str,&rect,DT_CALCRECT|DT_LEFT); //得到要繪制的文本在屏幕上的尺寸 51 m_pMemDC->DrawText(str,&rect,DT_LEFT); 52 InvalidateRect(rect,FALSE); //只刷新需要繪制文本的區(qū)域 53 如果繪圖次數(shù)很頻繁,位圖很大,,用這種方法可以明顯改善繪圖性能,。 54 Invalidate(TRUE)先清除DC再重畫,Invalidate(FALSE)直接在原圖上畫,,性能更好,,兩者可以視情況選用。
|