在前文中已經讨論了如何實作界面繪制雙緩存的問題,前文網址如下:
<a href="http://www.2cto.com/kf/201111/112429.html">http://www.2cto.com/kf/201111/112429.html</a>
雙緩存的主要思路是:先把圖形繪制到記憶體DC中,然後再把記憶體DC中的所有圖形一次性的複制到螢幕DC中。在前文的實作示例中,我們把直接往DC中繪制圖形的函數封裝為DrawDirect,把通過雙緩存來實作圖形繪制的函數封裝為DrawWithBufferEfficient,其中DrawWithBufferEfficient調用了DrawDirect函數。這種實作方式,保證了視圖類可實作雙緩存繪制。
如果在這工程中,還存在其他需要進行雙緩存的彈出視窗,根據前文的實作方式,也許隻能在彈出視窗類中,把DrawWithBufferEfficient重複實作一次,可能隻需要簡單的複制和拷貝,然後更改相應的類名。但是,這種重複性的工作,不是一件很愉快的事,尤其是當DrawWithBufferEfficient函數需要變更的時候。如果能對繪制雙緩存的函數進行獨立封裝,其他類隻要通過同一的接口調用或實作方法就可以完成雙緩存的實作,将會有效的提高代碼的複用性。
沒有使用雙緩存時,各類視窗是直接把圖形資料寫入到螢幕DC中,根據視窗圖形的不同,寫入的方式方法也不一樣,也就是DrawDirect函數的内容不一樣。使用雙緩存後,從記憶體DC複制到螢幕DC的動作是一樣的,即DrawWithBufferEfficient函數可以完全相同。考慮到需要調用不同的DrawDirect,可以把DrawDirect的指針作為DrawWithBufferEfficent的一個輸入參數,進而實作對DrawWithBufferEfficent函數的封裝。
下面來讨論一下實作的方式:
1、函數指針
首先我們需要了解函數指針的基本概念及是用方法,而由于DrawDirect是類的成員函數,還應該了解類成員函數指針的使用。
函數指針的讨論可參考之前的讨論文章,連結如下:
<a href="http://www.2cto.com/kf/201111/112430.html">http://www.2cto.com/kf/201111/112430.html</a>
2、函數指針模闆
由于DrawDirect可能是不同類的成員函數,是以,隻能通過函數模闆來實作調用不同類的DrawDirect。
函數指針模闆可參考之前的讨論文章,連結如下:
<a href="http://www.2cto.com/kf/201111/112431.html">http://www.2cto.com/kf/201111/112431.html</a>
3、可複用的雙緩存的實作
在工程添加一個類,用于實作雙緩存的接口函數模闆,該函數的輸入包括,要繪制的視窗類的指針,視窗類的繪制函數的指針,視窗類的螢幕DC的指針。
為了調用友善,可把函數子產品設定為靜态函數,調用時就可不用對該類進行執行個體化。
該類的源代碼如下所示:
template <typename T>
class CDoubleBufferTemplate
{
public:
typedef void (T::*DrawFun)(CDC*);
static void DrawWithBuffer(T* pT, DrawFun fun, CDC* pDC)
{
ASSERT_VALID(pT);
ASSERT_VALID(pDC);
/*建立記憶體DC*/
CDC dcMemory;
dcMemory.CreateCompatibleDC(pDC);
dcMemory.SetBkColor(pDC->GetBkColor());
/*設定記憶體DC的畫闆,大小與輸入DC的裁剪區域一樣*/
/*隻對裁剪區域進行重新繪制*/
CRect rectClip(0,0,0,0);
pDC->GetClipBox(&rectClip);
CBitmap bmpMemory;
bmpMemory.CreateCompatibleBitmap(pDC,
rectClip.Width(), rectClip.Height());
dcMemory.SelectObject(&bmpMemory);
/*設定記憶體DC的起始點*/
dcMemory.SetViewportOrg(-1*rectClip.left, -1*rectClip.top);
/*粉刷背景*/
dcMemory.FillSolidRect(&rectClip, pDC->GetBkColor());
(pT->*fun)(&dcMemory);
/*把記憶體DC複制到輸入DC中*/
pDC->BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(),
&dcMemory, rectClip.left, rectClip.top, SRCCOPY);
/*釋放資源*/
bmpMemory.DeleteObject();
dcMemory.DeleteDC();
}
};
視圖類可在OnDraw或OnPaint中對雙緩存模闆函數的調用,調用示例如下:
DoubleBufferTemplate<CDoubleBufferView>::DrawWithBuffer(
this, DrawDirect, pDC);
其中,this是視圖類的指針,DrawDirect是直接在DC中繪制圖形的函數,pDC是螢幕DC的指針。
5、參考文章