MFC如何高效地绘图

来源:互联网 发布:水族 知乎 编辑:程序博客网 时间:2024/04/27 09:55
MFC如何高效地绘图  
   
  [   作者:   TouchMe       添加时间:   2001-12-25   8:21:34   ]  
   
     
   
        显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。  
  而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的解决方案。  
  MFC的绘图效率的确不高但也不差,而且它的绘图函数使用非常简单,  
  只要使用方法得当,再加上一些技巧,用MFC可以得到效率很高的绘图程序。  
  我想就我长期(呵呵当然也只有2年多)使用MFC绘图的经验谈谈  
  我的一些观点。  
   
  1、显示的图形为什么会闪烁?  
        我们的绘图过程大多放在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);  
  }  
  呵呵,程序有点变态,但是能说明问题。  
        说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么  
  闪呢?这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要  
  闪得厉害一些,但是闪烁频率要低。  
        那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,  
  闪烁是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间  
  的差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧,  
  不闪才怪呢。  
   
   
  2、如何避免闪烁  
        在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC  
  提供的背景绘制过程了。实现的方法很多,  
    *   可以在窗口形成时给窗口的注册类的背景刷付NULL  
    *   也可以在形成以后修改背景  
  static   CBrush   brush(RGB(255,0,0));  
  SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);  
    *   要简单也可以重载OnEraseBkgnd(CDC*   pDC)直接返回TRUE  
        这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,  
  变得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有  
  图形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存中  
  绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去(这个  
  过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便用什么反差  
  大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为内存中最终的图形  
  与屏幕显示图形差别很小(如果没有运动,当然就没有差别),这样看起来就不会闪。  
   
   
  3、如何实现双缓冲  
        首先给出实现的程序,然后再解释,同样是在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();  
   
  上面的注释应该很详尽了,废话就不多说了。  
   
   
  4、如何提高绘图的效率  
        我主要做的是电力系统的网络图形的CAD软件,在一个窗口中往往要显示成千上万个电力元件,而每个元件又是由点、线、圆等基本图形构成。如果真要在一次重绘过程重画这么多元件,可想而知这个过程是非常漫长的。如果加上了图形的浏览功能,鼠标拖动图形滚动时需要进行大量的重绘,速度会慢得让用户将无法忍受。怎么办?只有再研究研究MFC的绘图过程了。  
        实际上,在OnDraw(CDC   *pDC)中绘制的图并不是所有都显示了的,例如:你  
  在OnDraw中画了两个矩形,在一次重绘中虽然两个矩形的绘制函数都有执行,但是很有可能只有一个显示了,这是因为MFC本身为了提高重绘的效率设置了裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示(往内存或者显存都叫显示)比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。但是这个裁剪区是MFC设置的,它已经为我们提高了显示效率,在进行复杂图形的绘制时如何进一步提高效率呢?那就只有去掉在裁剪区外的绘图过程了。可以先用pDC->GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。  
  如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高。
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 美的冰箱显示e6怎么办 冰箱电脑板坏了怎么办 笔记本网线接口坏了怎么办 蓝p吃了一片 怎么办 sd卡上锁了忘记密码怎么办 手机sd卡被锁定怎么办 冰箱制冷管堵了怎么办 冰箱的管子破了怎么办 淘宝京东e卡冻结怎么办 苏宁任性付冻结怎么办 苏宁订单删除了怎么办 联通销户话费有余额怎么办 暖气改地热不热怎么办 老楼房暖气不热怎么办 4s店修不好车怎么办 苏宁的发票丢了怎么办 京东退货没有发票怎么办 发票发错了邮箱怎么办 苹果手机忘记电子邮箱验证码怎么办 退差价把红包退还了怎么办 网上购票票丢了怎么办 岗位人手不够老板又不招人来怎么办 辞职后提成不发怎么办 老板给客户吵架员工该怎么办 冰柜声音大怎么办嗡嗡响 交了钱电没有怎么办 小白熊电动吸奶器显示F1怎么办 花洒的水变小了怎么办 手机插卡处坏了怎么办 吉利帝豪一键启动钥匙没电怎么办 居民医保断交5年怎么办 社保和医保断了怎么办 停缴了两年社保怎么办 医保交不够20年怎么办 医保断交4个月怎么办 医保断交5个月怎么办 换城市后社保卡怎么办 苹果6s呼叫失败怎么办 苹果手机打电话显示呼叫失败怎么办 苹果手机经常呼叫失败怎么办 苹果手机呼叫号码呼叫失败怎么办