在前文中已经讨论了如何实现界面绘制双缓存的问题,前文网址如下:

http://www.2cto.com/kf/201111/112429.html

双缓存的主要思路是:先把图形绘制到内存DC中,然后再把内存DC中的所有图形一次性的复制到屏幕DC中。在前文的实现示例中,我们把直接往DC中绘制图形的函数封装为DrawDirect,把通过双缓存来实现图形绘制的函数封装为DrawWithBufferEfficient,其中DrawWithBufferEfficient调用了DrawDirect函数。这种实现方式,保证了视图类可实现双缓存绘制。

如果在这工程中,还存在其他需要进行双缓存的弹出窗口,根据前文的实现方式,也许只能在弹出窗口类中,把DrawWithBufferEfficient重复实现一次,可能只需要简单的复制和拷贝,然后更改相应的类名。但是,这种重复性的工作,不是一件很愉快的事,尤其是当DrawWithBufferEfficient函数需要变更的时候。如果能对绘制双缓存的函数进行独立封装,其他类只要通过同一的接口调用或实现方法就可以完成双缓存的实现,将会有效的提高代码的复用性。

没有使用双缓存时,各类窗口是直接把图形数据写入到屏幕DC中,根据窗口图形的不同,写入的方式方法也不一样,也就是DrawDirect函数的内容不一样。使用双缓存后,从内存DC复制到屏幕DC的动作是一样的,即DrawWithBufferEfficient函数可以完全相同。考虑到需要调用不同的DrawDirect,可以把DrawDirect的指针作为DrawWithBufferEfficent的一个输入参数,从而实现对DrawWithBufferEfficent函数的封装。

下面来讨论一下实现的方式:

1、函数指针

首先我们需要了解函数指针的基本概念及是用方法,而由于DrawDirect是类的成员函数,还应该了解类成员函数指针的使用。

函数指针的讨论可参考之前的讨论文章,链接如下:

http://www.2cto.com/kf/201111/112430.html

2、函数指针模板

由于DrawDirect可能是不同类的成员函数,因此,只能通过函数模板来实现调用不同类的DrawDirect。

函数指针模板可参考之前的讨论文章,链接如下:

http://www.2cto.com/kf/201111/112431.html

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的指针。

4、工程源代码下载:http://up.2cto.com/2011/1128/20111128044129235.rar

5、参考文章
http://www.2cto.com/kf/201111/112429.html

http://www.2cto.com/kf/201111/112430.html

http://www.2cto.com/kf/201111/112431.html

摘自 www.cnblogs.com/xianyunhe/archive/2011/11/27/2265165.html

04-20 18:57