图形显示问题


显示图形如何避免闪烁,如何提高显示效率是最近遇到的问题。查阅了很多资料,然后现在稍微总结一下。
  
绘图过程一般是写在OnDraw或者OnPaint函数里,OnDraw是由OnPaint进行调用的。当窗口需要重绘时,首先用背景色将显示区清除,然后调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪烁。如果将背景刷设置成NULL,就可以解决闪烁这个问题。虽然不闪了,但是显示还是有问题,显示的内容会很混乱。因为重绘时没有背景色对原来绘制的图形进行清除,反而又加上了新的图形。 
绘图的显示速度对闪烁的影响不是很大的。
例如在OnDraw(CDC *pDC)中这样写: 
pDC->MoveTo(0,0); 
pDC->LineTo(100,100); 
这个绘图过程非常简单,但是拉动窗口变化时还是会看见闪烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的时间与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要闪烁5次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续重画,只会闪烁一次。
例如在OnDraw(CDC *pDC)中这样写: 
for(int i=0;i<100000;i++) 

pDC->MoveTo(0,i); 
pDC->LineTo(1000,i); 

闪烁主要就是反差造成的视觉现象。反差越大,闪烁越厉害。


下面就说说具体的解决办法。首先是上面提到的去掉MFC提供的背景绘制。实现的方法很多。
1、可以在窗口形成时给窗口的注册类的背景刷付NULL;
2、可以在形成以后修改背景 static CBrush brush(RGB(255,0,0)); 
SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush); 
3、可以重载OnEraseBkgnd(CDC* pDC)直接RETURN TRUE; 
这一步是解决了闪烁的问题。下面要解决绘制的问题了,就是用双缓存的方法。双缓冲就是先把要显示的图形在内存中绘制好,然后再一次性的将内存中的图形拷贝到屏幕上去。 


再接下来就说说双缓冲的实现。
在OnDraw(CDC *pDC)中: 
CDC MemDC; //首先定义一个显示设备对象 
CBitmap MemBitmap;//定义一个位图对象  
MemDC.CreateCompatibleDC(NULL); //建立与屏幕显示兼容的内存显示设备
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); //下面建立一个与屏幕显示兼容的位图 

//将位图选入到内存显示设备中 
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上 
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); 

//先用背景色将位图清除。
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); 

//绘图 
MemDC.MoveTo(……); 
MemDC.LineTo(……); 

//将内存中的图拷贝到屏幕上进行显示 
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); 

//绘图完成后的清理 
MemBitmap.DeleteObject(); 
MemDC.DeleteDC(); 

实际上,在OnDraw(CDC *pDC)中绘制的图并不是所有都显示了的,例如:在OnDraw中画了两个矩形,在一次重绘中虽然两个矩形的绘制函数都有执行,但是很有可能只有一个显示了,这是因为MFC本身为了提高重绘的效率设置了裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。进行复杂图形的绘制时可以去掉在裁剪区外的绘图过程来提高效率。可以先用pDC->GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。如果绘图过程不复杂,这样做可能对你的绘图效率不会有提高。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值