MFC 动态曲线 支持缩放 显示图例(CStatic派生类)

转自:http://blog.csdn.net/nuaazdh/article/details/7857223

首先声明,本项目不是作者独立完成的,而是借助别人的修改得到,也不保证目前的版本没有Bug,仅供大家参考和交流。若有不妥之处,还望指正。

之所以标为“原创”,是因为作者的确花了很大心思,并做了大幅修改和整理,望广大网友包涵,哈哈。。。

开发环境:Windows 7 ,Visual Studio 2008。

 

(一)开发需求和目标

  由于项目需要,需要开发一个GUI,要求能够同时显示至少两条曲线,而且要标出坐标,动态更新,支持缩放。。。。

(二)本项目实现了哪些功能

 继承CStatic控件,编写了一个绘图类,可以同时显示多条曲线,显示横纵坐标,坐标的范围可以自动调整,支持单击鼠标左键拖动放大,双击鼠标左键复原(这个想法来自MATLAB)。曲线和坐标轴属性可以自行设定。能够显示图例。

(三)效果截图

局部放大的结果:

(四)源代码

华为网盘:http://dl.dbank.com/c012cb0h8c

CSDN资源: http://download.csdn.net/detail/nuaazdh/4494341

这个博客不能添加附件,晕。。。  那个CSDN的文件要收两个积分的,大家不要介意哦。。。

备注,为了减小文件大小,我讲Debug和Release文件夹加下的文件,请大家编译后运行。

 

好了,一般人看到这里就可以了,下面赘述一下整个开发过程。

(一)关于参考程序

      本人对MFC不是很熟,只能“拿来主义”,本项目的就是基于http://www.albertsong.com/read-25.html这篇博文而作。感谢作者的付出。

上面这篇参考博文写的不错,而且附了源程序可供下载,但是实际运行我发现有内存泄漏!本人不是有意诋毁原作者的心血,只是实事求是,欢迎讨论。

内存泄漏的原因不得而知,不过我学到了内存泄漏的检测方法,顺便说一下:

 一是 Visual Studio自带的,这个微软MSDN上有说,包含如下语句:

[cpp]  view plain copy
  1. #define _CRTDBG_MAP_ALLOC   
  2. #include<stdlib.h>   
  3. #include<crtdbg.h>   
  4. #include "debug_new.h"   

然后在每个要检测的函数后面添加:

[cpp]  view plain copy
  1. _CrtDumpMemoryLeaks();  

这样在输出窗口会显示是否出现了内存泄漏,并定位;

二是下载Visual Leaker Detector,网址附上:http://vld.codeplex.com/documentation。怎么用,大家可以自己网上搜一下,不再赘述。

还有,微软MSDN上说,调用GetDC()后再ReleaseDC()也会造成内存泄漏,这个是个Bug,他们已经承认了,可以参考:http://support.microsoft.com/kb/819635/zh-cn


(二)双缓冲绘图

    既然参考的程序有内存泄漏的问题,那只能自己动手了。

   像我这种菜鸟,拿到这个项目,当然先去网上搜”MFC 动态曲线“,”VC++ 动态绘图“,”MFC GDI+ 绘图“等等,看多了,对双缓冲绘图也就耳濡目染了。

虽然我对具体实现还不是很了解,大概知道了其过程:现在内存中高个Bitmap对象,绘制完成后,拷贝到前端。这样就不用先擦出前端的图像,再一步一步绘制。双缓冲的好处

就是避免闪烁,这个大家都懂的。。。

  关于双缓冲绘图的过程大致如下:

[cpp]  view plain copy
  1. CPaintDC dc(this); // 绘图设备  
  2. CDC *pDC = GetDC();  
  3. CRect rect;  
  4. GetClientRect (&rect);        
  5.   
  6. //创建一个内存中的显示设备  
  7. CDC nDC;  
  8. nDC.CreateCompatibleDC(NULL);   
  9.   
  10. //创建一个内存中的图像  
  11. CBitmap nBitmap;  
  12. nBitmap.CreateCompatibleBitmap(pDC, rect.Width(),rect.Height());  
  13.   
  14. //指定内存显示设备在内存中的图像上画图  
  15. nDC.SelectObject(&nBitmap);   
  16.   
  17. // 刷新控件  
  18. RefreshPlot(&nDC);  
  19.   
  20. //将内存中画好的图像直接拷贝到屏幕指定区域上  
  21. pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&nDC, 0, 0, SRCCOPY);   
  22.   
  23. //释放相关资源  
  24. nBitmap.DeleteObject();  
  25. nDC.DeleteDC();  
  26. ReleaseDC(pDC);  

其他的没有好说的,重点是RefreshPlot()方法,这个是我自定义的函数。其内部完成:绘制背景、坐标轴、网格、曲线、网格坐标的显示、标题的显示、图例显示。。。。。

这部分代码是放在重载的OnPaint()函数中的。

 

(三)绘图结构和方法

  根据从网上查找的资料,我见过三种绘图结构。这里说的绘图结果,意思上,将上面的哪些代码(绘图的具体细节)贴到那个函数中去,我见过的三种情况是:重载:

DrawItem()方法,重载OnPaint()方法,重载OnEraseBkgnd()方法。貌似都可以,但是某些可能需要一些其他辅助的设置。本项目是采用的第二种方法。

  除了结构外最重要的便是具体怎么在一个CDC上绘图了。其实非常简单,只用几个函数,下面简单介绍一下:(pDC是CDC对象的指针)

pDC->MoveTo(int x,int y); 移动到一个点(CPoint的对象),x,y是点的坐标,关于MFC上绘图坐标大家应该非常熟悉了吧,左上为坐标原点,X轴向右,Y轴向下。

                                          当然也可以选择使用重载 MoveTo(POINT point)方法,预先把点算好,然后MoveTo()就好了。

pDC->LineTo(int x,int y); 这个函数意思很明显,画一条线,起点是上一给点,终点是当前的点(x,y),上一个点可以是MoveTo()确定的,或是LineTo()确定的。

                                        上面两个函数可以完成哪些工作呢?只要是直线都可以,如绘制坐标轴,绘制网格,和绘制曲线。绘制曲线其实就是调用多次LineTo()就OK啦

另一个函数是pDC->DrawText(),这个函数是用来显示文字的,当然绘制文字之前得告诉它目标位置、文字格式、颜色等等信息,这个后面会有介绍。

   有个这三个函数,基本就大功告成了,剩下的便是控制位置的格式和位置。这里要介绍三个对象:CPen,CFont和CRect。

CPen:画笔,其中的一个构造函数为CPen(int nPenStyle,int nWidth,COLORREF crColr),画线的时候用到,

CFont:字体,一般这么用 font.CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL) ,font为CFont的一个对象,这个在绘制文字的时候用到

CRect:矩形,构造的时候指明四个坐标值left,top,right,bottom就好了,这个在布局的时候和绘制文字会用到。

   现在就可以开始绘图啦,步骤:

①pDC->SelectObject(& font\pen),选择好画笔,格式由内部的参数font或者pen的引用指定;

②pDC->DrawText()或者pDC->MoveTo() + pDC->LineTo(),绘图;

③pDC->SelectObject(CPen * oldPen),恢复画笔。

 无论是绘制哪个部分,都套用上述三个步骤,就OK啦。

 

关于布局和缩放的功能就留作后面介绍吧。

 

参考:

[1]http://www.albertsong.com/read-25.html

[2]http://support.microsoft.com/kb/819635/zh-cn


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值