新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → [转帖]用MFC如何高效地绘图 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 6774 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [转帖]用MFC如何高效地绘图 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     longshentailang 帅哥哟,离线,有人找我吗?
      
      
      威望:1
      等级:计算机学士学位
      文章:325
      积分:2990
      门派:XML.ORG.CN
      注册:2006/6/20

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给longshentailang发送一个短消息 把longshentailang加入好友 查看longshentailang的个人资料 搜索longshentailang在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看longshentailang的博客楼主
    发贴心情 [转帖]用MFC如何高效地绘图


    显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题。
    而且多数人认为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()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。
    如果你的绘图过程不复杂,这样做可能对你的绘图效率不会有提高。


       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/4/5 18:33:00
     
     lizhong 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(猛啃高等数学)
      文章:19
      积分:121
      门派:XML.ORG.CN
      注册:2007/7/3

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给lizhong发送一个短消息 把lizhong加入好友 查看lizhong的个人资料 搜索lizhong在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看lizhong的博客2
    发贴心情 
    用mfc比较基础 学起来有高度
    我去年做工业实时监控项目的时候用的vc,在图形处理上后来选择了第三方控件.是一个矢量图控件. 控件做图形非常灵活并且用vc调用也很方便.

    http://www.visual-graph.com 网址上有例程

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/7/4 15:18:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客3
    发贴心情 
    哇,以前是同行啊,我以前也是做电力系统软件的,不过图形方面是显示实时监控画面的,我用的是OpenGL,要比直接画图好很多。

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/7/5 11:19:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/23 1:16:11

    本主题贴数3,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms