標籤:enter 其他 inf 顏色 畫圖 select 完成 這一 www.
轉自 MFC繪圖不閃爍——雙緩衝技術[轉]
在VC/MFC用CDC繪圖時,頻繁的重新整理,螢幕會出現閃爍的現象,CPU時間佔用率相當高,繪圖效率極低,很容易出現程式崩潰。
所謂雙緩衝技術,下面是百度百科的解釋:
我們看電視時,看到的螢幕稱為OSD層,也就是說,只有在OSD層上顯示映像我們才能看到。現在,我需要建立一個虛擬、看不見但是可以在上面畫圖(比如說畫點、線)的OSD層,我稱之為offscreen(背景緩衝區)。這個offscreen存在於記憶體中,我們在上面畫圖,這個offscreen上面的東西可以顯示在OSD層上,需要一個建立這個offscreen的函數,返回這個offscreen的控制代碼(整型指標)、寬度、高度、指向建立offscreen資料緩衝區的指標,該緩衝區是一個在函數外建立的offscreen的資料緩衝區,大小是offscreen的高度*寬度*每個像素點資料的大小。
閃爍是圖形編程的一個常見問題。需要多重複雜繪製操作的圖形操作會導致呈現的映像閃爍或具有其他不可接受的外觀。雙緩衝的使用解決這些問題。雙緩衝使用記憶體緩衝區來解決由多重繪製操作造成的閃爍問題。當啟用雙緩衝時,所有繪製操作首先呈現到記憶體緩衝區,而不是螢幕上的繪圖圖面。所有繪製操作完成後,記憶體緩衝區直接複製到與其關聯的繪圖圖面。因為在螢幕上只執行一個圖形操作,所以消除了由複雜繪製操作造成的映像閃爍。
在圖形圖象處理編程過程中,雙緩衝是一種基本的技術。我們知道,如果表單在響應WM_PAINT訊息的時候要進行複雜的圖形處理,那麼表單在重繪時由於過頻的重新整理而引起閃爍現象。解決這一問題的有效方法就是雙緩衝技術。因為表單在重新整理時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充表單繪圖區,然後在調用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。於是我們就看到了閃爍現象。
我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,表單上會變的一團糟。因為每次繪製圖象的時候都沒有將原來的圖象清除,造成了圖象的殘留,於是表單重繪時,畫面往往會變的亂七八糟。所以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,於是我們想到了使用BitBlt函數。它可以支援圖形塊的複製,速度很快。我們可以先在記憶體中作圖,然後用此函數將做好的圖複製到前台,同時禁止背景重新整理,這樣就消除了閃爍。以上也就是雙緩衝繪圖的基本的思路。
先按普通做圖的方法進行編程。即在視類的OnDraw函數中添加繪圖代碼。在此我們繪製若干同心圓,代碼如下:
CBCDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);CPoint ptCenter;CRect rect,ellipseRect;GetClientRect(&rect);ptCenter = rect.CenterPoint();for(int i=20;i>0;i--){ ellipseRect.SetRect(ptCenter,ptCenter); ellipseRect.InflateRect(i*10,i*10); pDC->Ellipse(ellipseRect);}
編譯運行程式,嘗試改變視窗大小,可以發現閃爍現象。
在雙緩衝方法中,首先要做的是屏蔽背景重新整理。背景重新整理其實是在響應WM_ERASEBKGND訊息。我們在視類中添加對這個訊息的響應,可以看到預設的代碼如下:
BOOL CMYView::OnEraseBkgnd(CDC* pDC){ return CView::OnEraseBkgnd(pDC);}
是調用父類的OnEraseBkgnd函數,我們屏蔽此調用,只須直接return TRUE;即可。
下面是記憶體緩衝作圖的步驟。
CPoint ptCenter;CRect rect,ellipseRect;GetClientRect(&rect);ptCenter = rect.CenterPoint();CDC dcMem; //用於緩衝作圖的記憶體DCCBitmap bmp; //記憶體中承載臨時圖象的位元影像
bmp.CreateCompatibleBitmap(&dcMem,rect.Width(),rect.Height());//建立相容位元影像dcMem.CreateCompatibleDC(pDC); //依附視窗DC建立相容記憶體DCdcMem.SelectObject(&bmp); //將位元影像選擇進記憶體DCdcMem.FillSolidRect(rect,pDC->GetBkColor()); //按原來背景填充客戶區,不然會是黑色for(int i=20;i>0;i--) //在記憶體DC上做同樣的同心圓圖象{ ellipseRect.SetRect(ptCenter,ptCenter); ellipseRect.InflateRect(i*10,i*10); dcMem.Ellipse(ellipseRect);}pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);//將記憶體DC上的圖象拷貝到前台dcMem.DeleteDC(); //刪除DCbm.DeleteObject(); //刪除位元圖
由於複雜的畫圖操作轉入後台,我們看到的是速度很快的複製操作,自然也就消除了閃爍現象。
MFC中的雙緩衝技術(解決繪圖閃爍問題)