【MFC學習】雙緩存繪圖淺談

最近使用到了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;
}




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