教你怎么实现高速高效双缓冲绘图

            不管是在MFC,还是在其他的框架中绘图,双缓冲,都是非常必要的绘图操作,像OPGL这种专业的绘图库,都是必备双缓冲的。

            那么为什么需要双缓冲呢?因为我们的绘图控件,其实是有一块背景的,如果没有背景,就是透明的。打个比方,我们的绘图区域是张白纸,如果没有背景,绘图区就变成了一块透明玻璃,试试你的客户区成透明的,会是多么悲惨的事情(如果有特殊需求,就成了亮点。。)。绘图的时候,我们的绘图操作和背景的刷新是有前后顺序的,假如我们画图的内容和背景色差很大,刷新的时候,就会看到闪烁,为了解决闪烁的问题,就需要使用双缓冲绘图了。

            双缓冲绘图的原理:自己在内存中建立一张位图,给位图设置好背景色,然后在这个位图上输出内容,然后将位图输出到绘图区域。如果是MFC的view画图,需要在WM_ERASE消息中,取消背景的刷新,就是直接return TRUE。

           双缓冲的绘图原理是这样,如果仅仅这样,只是解决了绘图不闪烁的问题,当然也提高了绘图速度,因为计算机绘图最慢的是将内容输出到屏幕。如果就这样使用双缓冲,无可厚非,在大多数场合都已经适用,但如果你要绘图的内容有几万个,甚至几十万个,这样的一次刷新,将会造成绘图很卡。比如一些专业的软件,像电路软件DXP2004,Protel99,或者需要多图形的软件,比如PS,当图形很大的时候,一次刷新都会让用户感觉到卡顿。那么怎么才能最高效的绘图呢?

          答案其实很简单:客户区双缓冲画图!因为不管怎么样,用户可以和直接操作的画面都是客户区,所以每次建立位图的时候,只需要建立客户区大小的位图就可以。然后判断你所需要绘制的内容是否在这个客户区内,不在客户区的就不画了。在客户区的才画,所以这就要求你建立数据结构的时候,每个绘制元素都要包含坐标,或者能知道每个元素的坐标。

          这其中的关键因素是:所有的元素在位图上绘制的时候,坐标都要减去客户区左上角的坐标。因为双缓冲的绘图,我们是在位图上画的,位图的原点,其实是客户区左上角的坐标,但是每个元素的坐标,是相对于视图的左上角的。我们要把相对视图原点的坐标转换为相对客户区左上角的坐标。比如客户区的矩形坐标是:500,500,1000,1000.这是一个500*500的矩形。我们以客户区矩形建立一个500*500的位图,我们有一个元素的坐标是600,600.这个时候,我们的输出必须是:pdc->draw(600-500,600-500).就是元素的实际坐标,要减去客户区左上角的坐标,然后才能绘制到位图中去,才能保证绘图正确!

         示例代码:

         在View的OnDraw(CDC* pDC)中:

/************************************************************************/
 /* 获得客户区                                                                     */
 /************************************************************************/
GetClientRect(&m_rClipRect);   //此时虽然得到了客户区坐标,但是矩形是(0,0,宽度,高度)的坐标。

OnPrepareDC(pDC);//这句是ScrollView将当前的滚动条信息整理好,得到正确的逻辑坐标。

pDC->DPtoLP(&m_rClipRect);   //将客户区坐标转换成逻辑坐标。此时才得到了正确的客户区坐标。

/************************************************************************/
 /* 创建背景DC,创建内存位图,将内存位图选入背景DC,填充背景颜色                                                                     */
 /************************************************************************/

CDC dcBack;
 
 dcBack.CreateCompatibleDC(NULL);

 CBitmap bitmap;

 //创建了一块客户区大小的画布
 bitmap.CreateCompatibleBitmap(pDC,m_rClipRect.Width(),m_rClipRect.Height());

 dcBack.SelectObject(bitmap);

 dcBack.FillSolidRect(0,0,m_rClipRect.Width(),m_rClipRect.Height(),RGB(255,255,255));

//然后就可以使用dcBack来绘图了。比如输出文字.dcBack.TextOut(10,10,"双缓冲").

//判断你要绘制的元素是否在客户区中,不在的就不画

if(要绘制的元素在客户区)    //这里是关键。

{

      //将元素绘制在背景DC中.

     dcBack.Draw(元素的坐标减去客户区原点坐标);

}

//将背景DC中的内容输出到客户区.

pDC->BitBlt(m_rClipRect.left,m_rClipRect.top,m_rClipRect.Width(),m_rClipRect.Height(),&dcBack,0,0,SRCCOPY );

dcBack.DeleteDC();    //删除创建的DC对象,为了内存,删除吧。

 bitmap.DeleteObject(); //删除位图对象,因为已经输出到屏幕了,所以要删除。下次如果要刷新屏幕,又重建了,所以这个位图是没有用的,按内存的友好度,也应该删除自己创建的对象。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值