解决MFC绘图过程中的闪烁.doc

上传人:新** 文档编号:544447363 上传时间:2024-03-07 格式:DOC 页数:17 大小:54.51KB
返回 下载 相关 举报
解决MFC绘图过程中的闪烁.doc_第1页
第1页 / 共17页
解决MFC绘图过程中的闪烁.doc_第2页
第2页 / 共17页
解决MFC绘图过程中的闪烁.doc_第3页
第3页 / 共17页
解决MFC绘图过程中的闪烁.doc_第4页
第4页 / 共17页
解决MFC绘图过程中的闪烁.doc_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《解决MFC绘图过程中的闪烁.doc》由会员分享,可在线阅读,更多相关《解决MFC绘图过程中的闪烁.doc(17页珍藏版)》请在金锄头文库上搜索。

1、如何解决绘图过程中的闪烁在VC中进行绘图过程处理时,如果图形刷新很快,经常出现图形闪烁的现象。利用先在内存绘制,然后拷贝到屏幕的办法可以消除屏幕闪烁,具体的方法是先在内存中创建一个与设备兼容的内存设备上下文,也就是开辟一快内存区来作为显示区域,然后在这个内存区进行绘制图形。在绘制完成后利用BitBlt函数把内存的图形直接拷贝到屏幕上即可。具体的代码实现为:(1)创建内存区域CDC* pMem=new CDC; CBitmap* pBmp=new CBitmap;CBitmap* pOldBmp;CDC* pDC=GetDC();CRect rectTemp;为绘图区域pMem-CreateCo

2、mpatibleDC(pDC);pBmp-CreateCompatibleBitmap(pDC, rectTemp.Width(), rectTemp.Height();pOldBmp=pMem-SelectObject(pBmp);(2)进行图形绘制pMem-LineTo(.); 进行绘图处理(3)拷贝到屏幕 pDC-BitBlt(rectTemp.left,rectTemp.top,rectTemp.Width(),rectTemp.Height(),pMem,0,0,SRCCOPY);pMem-SelectObject(pOldBmp);pBmp-DeleteObject() ;pMem

3、-DeleteDC();=双缓存机制解决VC+绘图时的闪烁问题显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的解决方案。MFC的绘图效率的确不高但也不差,而且它的绘图函数使用非常简单,只要使用方法得当,再加上一些技巧,用MFC可以得到效率很高的绘图程序。我想就我长期(呵呵当然也只有2年多)使用MFC绘图的经验谈谈我的一些观点。1、显示的图形为什么会闪烁?我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏幕显示时是由OnPaint进行调用的。当窗口由于任何原因需要重绘时,总是先用背景色将显示区清除,然

4、后才调用OnPaint,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使得窗口的显示乱成一团,因为重绘时没有背景色对原来绘制的图形进行清除,而又叠加上了新的图形。有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的,其实这样说并不对,绘图的显示速度对闪烁的影响不是根本性的。例如在OnDraw(CDC *pDC)中这样写:pDC-MoveTo(0,0);pDC-LineTo(100,100);这个绘图过程应该是非常简单、非常快了吧,但是拉动窗口变化时还是会看见闪

5、烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的时间与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要闪烁5次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续重画只会闪烁一次。这个也可以试验,在OnDraw(CDC *pDC)中这样写:for(int i=0;iMoveTo(0,i);pDC-LineTo(1000,i);呵呵,程序有点变态,但是能说明问题。说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么闪呢?这是因为复杂图形占的面积大,重画时造成的反差比

6、较大,所以感觉上要闪得厉害一些,但是闪烁频率要低。那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,闪烁是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间的差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧,不闪才怪呢。2、如何避免闪烁在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC提供的背景绘制过程了。实现的方法很多,* 可以在窗口形成时给窗口的注册类的背景刷付NULL* 也可以在形成以后修改背景static CBrush brush(RGB(255,0,0);SetClassLong(this-m_hWnd,GCL_

7、HBRBACKGROUND,(LONG)(HBRUSH)brush);* 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形与屏幕显示图形

8、差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。3、如何实现双缓冲首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:CDC MemDC; /首先定义一个显示设备对象CBitmap MemBitmap;/定义一个位图对象/随后建立与屏幕显示兼容的内存显示设备MemDC.CreateCompatibleDC(NULL);/这时还不能绘图,因为没有地方画 _/下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);/将位图选入到内存显示设备中/

9、只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上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.DeleteOb

10、ject();MemDC.DeleteDC();上面的注释应该很详尽了,废话就不多说了。4、如何提高绘图的效率我主要做的是电力系统的网络图形的CAD软件,在一个窗口中往往要显示成千上万个电力元件,而每个元件又是由点、线、圆等基本图形构成。如果真要在一次重绘过程重画这么多元件,可想而知这个过程是非常漫长的。如果加上了图形的浏览功能,鼠标拖动图形滚动时需要进行大量的重绘,速度会慢得让用户将无法忍受。怎么办?只有再研究研究MFC 的绘图过程了。实际上,在OnDraw(CDC *pDC)中绘制的图并不是所有都显示了的,例如:你在OnDraw中画了两个矩形,在一次重绘中虽然两个矩形的绘制函数都有执行,但

11、是很有可能只有一个显示了,这是因为MFC本身为了提高重绘的效率设置了裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示(往内存或者显存都叫显示)比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。但是这个裁剪区是MFC设置的,它已经为我们提高了显示效率,在进行复杂图形的绘制时如何进一步提高效率呢?那就只有去掉在裁剪区外的绘图过程

12、了。可以先用 pDC-GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高。=VC+大数据量绘图时无闪烁刷屏技术实现引言当我们需要在用户区显示一些图形时,先把图形在客户区画上,虽然已经画好但此时我们还无法看到,还要通过程序主动地刷新用户区,强制Windows发送一条WM_PAINT消息,这将引发视类OnDraw函数简单地将所有的图形对象重画,这样才完成了图形的显示工作,但在刷新的同时会引起较明显的闪烁尤其是当画面面积较大、图像元素过多时尤为明显甚至达到无法正常工作的地步。因此,我们需要做相

13、应的处理。本文介绍了采用先在内存中绘制图形,然后再把绘好的图形以位图方式从内存拷贝到窗口客户的消除刷屏闪烁的一种方法。WM_PAINT消息和无效区在用户移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见。用户改变窗口的大小。滚动窗口用户区。程序调用InvalidateRect或InvalidateRgn函数显式地发送一条WM_PAINT消息。当上面情况之一发生时,就要求应用程序一定刷新其用户区的一部分或全部,Windows会向窗口函数发送一条WM_PAINT消息。另外,当 Windows删除覆盖窗口部分区域的对话框或消息框时和菜单下拉出来又被释放时窗口用户区被临时覆盖,系统会试图保存显示区域

14、,但是不一定能成功,可能向窗口函数发送一条WM_PAINT消息,要求应用程序刷新其用户区。需要说明的是:光标或图符穿过窗口用户区时,也可能覆盖显示内容,但这种情况下,系统一定能保留并恢复被覆盖的区域,所以此时并不会发送WM_PAINT消息来要求应用程序去刷新其显示区。在Windows 应用程序的窗口函数中,对WM_PAINT消息的处理就是刷新其用户区,这是一种固定的程序结构。为提高刷新效率,我们可以只刷新用户区的一小部分,其余没有发生变化的我们可以不予刷新,窗口函数可以通过调用函数InvalidateRect显式地使用户区内的一个矩形无效。而且只有当窗口客户区的某一部分失效时,其窗口函数才会收到WM_PAINT消息。刷屏闪烁的产生原因与解决方法当客户区有所改动,而又要将改动显示出来,就必然要强制Windows发送一条WM_PAIN

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号