最近使用到了MFC的C++的雙緩存繪圖,這裏簡單做一下記錄。
雙緩存繪圖的優點是可以降低圖片顯示過程中的閃動現象。
原因:
在圖形圖象處理編程過程中,雙緩衝是一種基本的技術。我們知道,如果窗體在響應WM_PAINT消息的時候要進行復雜的圖形處理,那麼窗體在重繪時由於過頻的刷新而引起閃爍現象。解決這一問題的有效方法就是雙緩衝技術。
因爲窗體在刷新時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區,然後在調用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。於是我們就看到了閃爍現象。
我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,窗體上會變的一團糟。因爲每次繪製圖象的時候都沒有將原來的圖象清除,造成了圖象的殘留,於是窗體重繪時,畫面往往會變的亂七八糟。所以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,於是我們想到了使用BitBlt函數。它可以支持圖形塊的複製,速度很快。我們可以先在內存中作圖,然後用此函數將做好的圖複製到前臺,同時禁止背景刷新,這樣就消除了閃爍。以上也就是雙緩衝繪圖的基本的思路。
引自:http://www.cppblog.com/wrhwww/archive/2011/03/01/140913.html
雙緩存繪圖思路:
1.創建內存DC。
2.創建Bitmap用來作爲畫圖的畫布。(如果用物理DC去創建可以畫彩×××,如果用內存DC是黑白的)
3.把bitmap選入內存DC中。
4.進行畫圖。(可以把圖片畫在bitmap上,作爲背景,也可以通過,moveto,lineto等進行畫)
5.把內存DC上的內容複製到物理DC上。
6.關閉DC連接,清理創建的內存DC和bitmap。
注意:
1.內存DC如果和物理DC大小一致的話不用進行縮放,如果是不一致的話還要進行縮放處理。縮放與否使用bltblt和StretchBlt方法,一個是可以縮放的。這裏不展開。
2.注意關閉DC連接,否則很容易造成資源泄露。尤其是GDI資源。
代碼說明:
1.可以先關掉背景擦除事件,也可以不處理。
屏蔽背景刷新。背景刷新其實是在響應WM_ERASEBKGND消息。我們在視類中添加對這個消息的響應,可以看到缺省的代碼如下:
BOOL CMYView::OnEraseBkgnd(CDC* pDC) { return CView::OnEraseBkgnd(pDC); }
是調用父類的OnEraseBkgnd函數,我們屏蔽此調用,只須直接return TRUE;即可。
2.使用雙緩存技術繪圖
void CMonitorPolicyDlg::DrawFigure(vector<CIrregularFigure> m_FiguresVector) { /*創建畫筆樣式*/ CPen cDrawPen; cDrawPen.CreatePen(PS_SOLID,3,RGB(0,255,0)); CDC memDC; CBitmap cMemBitmap;/*用來畫圖的bitmap*/ CBitmap *pOldBitmap;/*用來替換舊的object*/ CPen *pOldPen; CPoint cPoint1(1,1); CPoint cPoint2(10,10); /*獲取顯示控件的DC*/ CDC * pDC = GetDlgItem(IDC_IMG_SHOW_WINDOW)->GetDC(); /*先創建內存dc*/ memDC.CreateCompatibleDC(NULL); /*創建bitmap,大小與所要顯示控件大小一致,pDC使用物理dc生成彩×××像,用內存dc生成黑白圖像*/ cMemBitmap.CreateCompatibleBitmap(pDC,m_cImgRect.Width(),m_cImgRect.Height());/*m_cImgRect爲顯示控件的矩形大小*/ /*把bitmap作爲畫圖紙,綁定到memDC上*/ pOldBitmap = memDC.SelectObject(&cMemBitmap);/*selectobject會返回原先的bitmap,裝載新的bitmap*/ /*初始化memDC上的背景顏色*/ memDC.FillSolidRect(0,0,m_cImgRect.Width(),m_cImgRect.Height(),pDC->GetBkColor()); /*這裏如果需要加載圖片的話,可以在這裏加載,這樣圖片就變爲了背景*/ //例如CImage.draw(); pOldPen = memDC.SelectObject(&cDrawPen); /*畫了一條直線*/ memDC.MoveTo(cPoint1); memDC.LineTo(cPoint2); /*把內存繪製到物理控件上*/ pDC->BitBlt(0,0,m_cImgRect.Width(),m_cImgRect.Height(),&memDC,0,0,SRCCOPY); /*釋放內存dc*/ memDC.SelectObject(pOldBitmap);/*把創建的bitmap替換出來*/ cMemBitmap.DeleteObject();/*對應cMemBitmap.CreateCompatibleBitmap,釋放空間*/ memDC.DeleteDC();/*對應memDC.CreateCompatibleDC,釋放內存dc*/ ReleaseDC(pDC);/*對應CDC * pDC = GetDlgItem(IDC_IMG_SHOW_WINDOW)->GetDC()*/ return; }