MFC--自己优化的双缓冲绘图方法
自己通过尝试,用修改视图坐标的方法, 优化了双缓冲绘图,实现起来并不复杂。
在介绍这个方法前,重新介绍一下窗口和视口的概念.
窗口:就是我们通过拖滚动条所能看到的整个窗口.它是有一部分不能被当前显示的.
视口:就是我们能直接看到的当前显示的窗口,它是窗口的一部分,滚动窗口的视口肯定比窗口小一些,普通窗口的视口大小就是窗口大小.
下面介绍优化方法
网上给出的双缓冲绘图方法多是在内存中绘出一幅和窗口大小相同的位图再导入设备.对于滚动窗口,我前些日子写的日志也给出了方法.这样做,虽然达到了目 的,但是却很大程度上的浪费了内存资源.比如,窗口大小800*600,滚动窗口1600*800.如果只是刷新了1*1的视口区域,将需要在内存中绘 800*600的位图,对于滚动窗口,更是需要1600*800的位图,而只有1*1的区域是有效的.资源浪费了几十万倍.优化的方法就是在内存中只绘一 幅和刷新区域同样大小的位图.
优化步骤:
一.在OnDraw(CDC* pDC)函数中定义相关变量.
刷新区域 CRect rc,
兼容DC CDC memDC,
兼容位图 CBitmap memBmp,
二.调用GetClipBox(&rc)获得刷新区域,注意,获得的区域是以逻辑坐标表示的,不是设备坐标。rc的左上角坐标即兼容DC视口坐标相对逻辑坐标的偏移,将这个坐标设为兼容DC的视口坐标原点,这样不做其它调整就可以按照逻辑坐标在兼容DC里绘图了。这样绘图时将逻辑坐标加上偏移量就是兼容DC的设备坐标.调用CreateCompatibleDC()创建兼容DC,调用 CreateCompatibleBitmap()创建兼容位图,调用SelectObject()导入位图.
三.绘图.先调用FillSolidRect()用指定的颜色刷背景,再判断下要画在图在不在rc范围内,如果不在,不画,画也没有意义,画图.
四.调用BitBlt()导入位图,销毁位图对象,DC.
五.最后,响应 WM_ERASEBKGND 消息,直接返回TRUE,取消刷新背景.
说明:双缓冲绘图本身都具有一定的复杂性,如果所绘的图形并不复杂,使用这种方法不会有明显的效果提升.
很简单吧,给出示例代码,在文档类中保存的矩形对象m_ellipse内画椭圆.
void CTest2View::OnDraw(CDC* pDC)
{
// TODO: add draw code for
native data here
CDC memDC;
CBitmap memBmp;
memDC.CreateCompatibleDC(pDC);//创建兼容DC
CRect rc;
pDC->GetClipBox(&rc);//获得刷新区域
// 创建兼容位图
memBmp.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
memDC.SelectObject(&memBmp);//导入位图
//红色背景
memDC.FillSolidRect(0,0,rc.Width(),rc.Height(),RGB(255,0,0));
memDC.SetWindowOrg(rc.left, rc.top);
//start画图 这是画一个椭圆的示例代码
CRect ellipse = GetDocument()->m_ellipse;
if( !( (rc.left >
ellipse.right ) //右侧超出
|| (rc.right < ellipse.left
) //左侧超出
|| (rc.top > ellipse.bottom) //下侧超出
|| (rc.bottom< ellipse.top ) )) //上侧超出
{
memDC.Ellipse(&ellipse); //画图
}
//end画图
//导入
pDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, rc.left,
rc.top, SRCCOPY);
memBmp.DeleteObject();//销毁位图
memDC.DeleteDC();//销毁DC
}
BOOL CTestView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message
handler code here and/or call
return TRUE;
// return CView::OnEraseBkgnd(pDC);
}