C++ GUI 绘图控件目录

MFC


  • VS2010 使用TeeChart绘图控件 - 之一 - 控件和类的导入

  • VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图,柱状图)

  • TeeChart绘图控件 - 之三 - 提高绘图的效率

  • MFC下好用的高速绘图控件-(Hight-Speed Charting)

  • 绘制动态曲线


Qt


  • qt超强精美绘图控件 - QCustomPlot一览

  • qt超强绘图控件qwt - 安装及配置

也许这是vc下最好最方便的绘图类,它有TeeChart的绘图和操作风格,不用当心注册破解的问题,因为它是开源的。不用打包注册,因为它是封装成类的,能方便扩展继承。vc6.0到vs2010都能使用,而且非常简单。

此类发表于codeproject

在使用它的时候,展示一下它的效果吧:



如果你想需要上面这些效果的,果断选它吧!


下面用图文并茂的方式,来详细介绍这个绘图控件

首先,下载这个控件,最新可以从这里获取codeproject

1 ChartCtrl类的导入


在工程下建立一个文件夹

叫ChartCtrl吧,里面放置ChartCtrl的源代码



文件夹内容如图所示



然后让vs导入这些类





全选,确定-ok






这时工程就添加好这个控件了



2.创建控件


2.1 对话框编辑器创建

对于一些不需要改变大小的对话框来说,在对话框编辑器里拖曳创建控件是最舒服的方法了,这个ChartCtrl可以用用户控件来创建
首先在对话框上放置一个Custom Control




修改属性如下图所示。这里要改的属性有Style,就在5右边的0改为2,0x52010000,Class命名为ChartCtrl,ID随便改了


给对话框添加变量,和传统的方法一样。这里需要注意的是,由于文件都放置在工程文件的一个文件夹下,包含头文件时需要指明路径




头文件包含的样式如下:

[cpp] view plain copy 

  1. #include "ChartCtrl/ChartCtrl.h"  

在对话框类添加变量,叫m_ChartCtrl1(后面还有m_ChartCtrl2通过动态创建的)

[cpp] view plain copy 

  1. CChartCtrl m_ChartCtrl2;  

 在DoDataExchange函数里添加关联

[cpp] view plain copy 

  1. void CSpeedChartCtrlDemoDlg::DoDataExchange(CDataExchange* pDX)   

  2. {  

  3.     CDialogEx::DoDataExchange(pDX);  

  4.     DDX_Control(pDX, IDC_ChartCtrl1, m_ChartCtrl1);  

  5. }  

编译运行,绘图控件就出来了



2.2 动态创建

添加头文件:

同样头文件如下写:

[cpp] view plain copy 

  1. #include "ChartCtrl/ChartCtrl.h"  

然后添加成员变量

[cpp] view plain copy 

  1. CChartCtrl m_ChartCtrl2;  

在resource.h里添加一个资源



添加IDC_ChartCtrl2,为1001,注意记得把_APS_NEXT_CONTROL_VALUE改成下一个资源号


在OnInitDialog里创建

如:

[cpp] view plain copy 

  1. CRect rect,rectChart;   

  2. GetDlgItem(IDC_ChartCtrl1)->GetWindowRect(&rect);  

  3. ScreenToClient(rect);  

  4. rectChart = rect;  

  5. rectChart.top = rect.bottom + 3;  

  6. rectChart.bottom = rectChart.top + rect.Height();  

  7. m_ChartCtrl2.Create(this,rectChart,IDC_ChartCtrl2);  

  8. m_ChartCtrl2.ShowWindow(SW_SHOWNORMAL);  


这样就可以创建了,下图两个控件分别通过对话框编辑器创建和动态创建,代码在附件下载里

此时什么也不会显示,需要添加坐标轴

3.创建坐标轴

 

ChartCtrl一共有3种坐标,都继承于CChartAxis


头文件ChartCtrl.h已经包含这些坐标,不需要引入

下面分别建立两种坐标轴,一个是数值型一个是时间型

在m_ChartCtrl1建立两个都是数值型的坐标

在创建m_ChartCtrl1之后加入如下创建坐标轴的代码:(这里写在OnInitDialog里)

[cpp] view plain copy 

  1. CChartAxis *pAxis= NULL;   

  2. pAxis = m_ChartCtrl1.CreateStandardAxis(CChartCtrl::BottomAxis);  

  3. pAxis->SetAutomatic(true);  

  4. pAxis = m_ChartCtrl1.CreateStandardAxis(CChartCtrl::LeftAxis);  

  5. pAxis->SetAutomatic(true);  

这样就建立两个坐标轴了,如图所示



给m_ChartCtrl2创建时间坐标

[cpp] view plain copy 

  1. CChartDateTimeAxis* pDateAxis= NULL;  

  2. pDateAxis = NULL;   

  3. pDateAxis = m_ChartCtrl2.CreateDateTimeAxis(CChartCtrl::BottomAxis);  

  4. pDateAxis->SetAutomatic(true);  

  5. pDateAxis->SetTickLabelFormat(false,_T("%m月%d日"));  

  6. pAxis = m_ChartCtrl2.CreateStandardAxis(CChartCtrl::LeftAxis);  

  7. pAxis->SetAutomatic(true);  

SetTickLabelFormat函数用来设置时间显示方式,格式化和COleDateTime的Format一样


4.创建标题

#include "ChartClass\ChartTitle.h"


在添加标题时,先要说说ChartCtrl的字符串,ChartCtrl的字符串实际是stl的string和wstring,为了对应unicode,作者对这两种字符进行了一个宏定义,就像TCHAR一样,定义如下:


[cpp] view plain copy 

  1. #include  

  2. #include   

  3.   

  4. #if defined _UNICODE ||defined UNICODE  

  5.     typedef std::wstring TChartString;  

  6.     typedef std::wstringstream TChartStringStream;  

  7. #else  

  8.     typedef std::string TChartString;  

  9.     typedef std::stringstream TChartStringStream;  

  10. #endif  


所以在多字节情况下,就是string。由于MFC大部分都是用CString,CString也是经过宏定义,所以可以比较轻松的和TChartString转换,另外TChartStringStream远比CString的Format灵活和直观,建议大家研究研究!


 加入如下代码:


[cpp] view plain copy 

  1. TChartString str1;  

  2. str1 = _T("IDC_ChartCtrl1 - m_ChartCtrl1");  

  3. m_ChartCtrl1.GetTitle()->AddString(str1);  

  4.   

  5. CString str2(_T(""));  

  6. str2 = _T("IDC_ChartCtrl2 - m_ChartCtrl2");  

  7. m_ChartCtrl2.GetTitle()->AddString(TChartString(str2));  


TChartString 可以直接用“=”对字符串赋值



QT MFC 绘图技术比较_第1张图片


设置坐标轴的标题,首先需要获取坐标GetLeftAxis,GetBottomAxis ……
获取坐标后,获得坐标的文字标签GetLabel,然后进行修改
如下两种写法,一种比较安全繁琐,一种就直接过去就可以,看个人喜好

[cpp] view plain copy 

  1. CChartAxisLabel* pLabel = NULL;  

  2. CChartAxis *pAxis = NULL;  

  3. TChartString str1 = _T("左坐标轴");  

  4.   

  5. CChartAxisLabel* pLabel = NULL;  

  6.   

  7. pAxis = m_ChartCtrl1.GetLeftAxis();  

  8. if(pAxis)  

  9.     pLabel = pAxis->GetLabel();  

  10. if(pLabel)  

  11.     pLabel->SetText(str1);  

  12.   

  13. m_ChartCtrl2.GetLeftAxis()->GetLabel()->SetText(str1);  

  14.   

  15. str1 = _T("数值坐标轴");  

  16. pAxis = m_ChartCtrl1.GetBottomAxis();  

  17. if(pAxis)  

  18.     pLabel = pAxis->GetLabel();  

  19. if(pLabel)  

  20.     pLabel->SetText(str1);  

  21. str1 = _T("时间坐标轴");  

  22.   

  23. m_ChartCtrl2.GetBottomAxis()->GetLabel()->SetText(str1);  




设置完效果如图

QT MFC 绘图技术比较_第2张图片


标题还可以更改颜色,这里不再重复描述。


5.画图

5.1 创建线图

ChartCtrl的画线非常简单通用,远比TeeChart简单和方便。

创建线图先要创建一个图形系列,这个和TeeChart很像

用函数CChartCtrl的CreateLineSerie()函数即可创建一个线图,这个函数会返回这个系列的指针,所有在创建之后记得保存下这个指针,以便之后的操作。线图系列的指针是CChartLineSerie,记得包含头文件

#include "ChartClass\ChartLineSerie.h"

创建完序列之后就可以用AddPoints函数把double数组的数据画出来,这个比TeeChart方便多了

 

如下这是画图的函数

[cpp] view plain copy 

  1. m_ChartCtrl1.EnableRefresh(false);  

  2. m_ChartCtrl2.EnableRefresh(false);  

  3. //////////////////////////////////////////////////////////////////////////  

  4. //画图测试  

  5. //////////////////////////////////////////////////////////////////////////  

  6. double x[1000], y[1000];  

  7. for (int i=0; i<1000; i++)  

  8. {  

  9.     x[i] = i;  

  10.     y[i] = sin(float(i));  

  11. }  

  12. CChartLineSerie *pLineSerie1;  

  13. m_ChartCtrl1.RemoveAllSeries();//先清空  

  14. pLineSerie1 = m_ChartCtrl1.CreateLineSerie();  

  15. pLineSerie1->SetSeriesOrdering(poNoOrdering);//设置为无序  

  16. pLineSerie1->AddPoints(x, y,1000);  

  17. pLineSerie1->SetName(_T("这是IDC_ChartCtrl1的第一条线"));//SetName的作用将在后面讲到  

  18.   

  19. //////////////////////////////////////////////////////////////////////////  

  20. //时间轴画图  

  21. //////////////////////////////////////////////////////////////////////////  

  22. COleDateTime t1(COleDateTime::GetCurrentTime());  

  23. COleDateTimeSpan tsp(1,0,0,0);  

  24. for (int i=0; i<1000; i++)  

  25. {  

  26.     x[i] = t1.m_dt;  

  27.     y[i] = sin(float(i));  

  28.     t1 += tsp;  

  29. }  

  30. CChartLineSerie *pLineSerie2;  

  31. m_ChartCtrl2.RemoveAllSeries();//先清空  

  32. pLineSerie2 = m_ChartCtrl2.CreateLineSerie();  

  33. pLineSerie2->SetSeriesOrdering(poNoOrdering);//设置为无序  

  34. pLineSerie2->AddPoints(x, y,1000);  

  35. pLineSerie2->SetName(_T("这是IDC_ChartCtrl2的第一条线"));//SetName的作用将在后面讲到  

  36.   

  37. m_ChartCtrl1.EnableRefresh(true);  

  38. m_ChartCtrl2.EnableRefresh(true);  



 

QT MFC 绘图技术比较_第3张图片




RemoveAllSeries函数可以清楚所有线条,EnableRefresh函数可以提供绘图效率,另外告诉大家一个bug,时间轴坐标在调第二次用RemoveAllSeries函数后,画图时一定要EnableRefresh(false)再EnableRefresh(true);否则会断言




下面将介绍更多的会图方法

在上一篇已经介绍了简单的线条绘制,实际上可能需要多的功能

5.2 添加曲线

控件可以绘制不止一条曲线,可以绘制足够多的曲线在上面,下面演示如何添加多个曲线

只要在画图时不清楚原来的曲线就会添加多一条曲线

把代码的RemoveAllSeries去掉就会添加多条曲线

[cpp] view plain copy 

  1. m_ChartCtrl1.EnableRefresh(false);  

  2. m_ChartCtrl2.EnableRefresh(false);  

  3. //////////////////////////////////////////////////////////////////////////  

  4. //画图测试  

  5. //////////////////////////////////////////////////////////////////////////  

  6. double x[1000], y[1000];  

  7. for (int i=0; i<1000; i++)  

  8. {  

  9. x[i] = i;  

  10. y[i] = sin(float(i)*m_ChartCtrl1.GetSeriesCount());  

  11. }  

  12. CChartLineSerie *pLineSerie1;  

  13. // m_ChartCtrl1.RemoveAllSeries();//不清空  

  14. pLineSerie1 = m_ChartCtrl1.CreateLineSerie();  

  15. pLineSerie1->SetSeriesOrdering(poNoOrdering);//设置为无序  

  16. pLineSerie1->AddPoints(x, y,1000);  

  17. TChartStringStream strs1;  

  18. strs1 << _T("这是IDC_ChartCtrl1的第")  

  19. << m_ChartCtrl1.GetSeriesCount()  

  20. << _T("条曲线");  

  21. pLineSerie1->SetName(strs1.str());  

  22.   

  23. //////////////////////////////////////////////////////////////////////////  

  24. //时间轴画图  

  25. //////////////////////////////////////////////////////////////////////////  

  26. COleDateTime t1(COleDateTime::GetCurrentTime());  

  27. COleDateTimeSpan tsp(1,0,0,0);  

  28. for (int i=0; i<1000; i++)  

  29. {  

  30. x[i] = t1.m_dt;  

  31. y[i] = sin(float(i)*m_ChartCtrl2.GetSeriesCount());  

  32. t1 += tsp;  

  33. }  

  34. CChartLineSerie *pLineSerie2;  

  35. // m_ChartCtrl2.RemoveAllSeries();//不清空  

  36. pLineSerie2 = m_ChartCtrl2.CreateLineSerie();  

  37. pLineSerie2->SetSeriesOrdering(poNoOrdering);//设置为无序  

  38. pLineSerie2->AddPoints(x, y,1000);  

  39. TChartStringStream strs2;  

  40. strs2 << _T("这是IDC_ChartCtrl2的第")  

  41. << m_ChartCtrl2.GetSeriesCount()  

  42. << _T("条曲线");  

  43. pLineSerie2->SetName(strs2.str());  

  44.   

  45. m_ChartCtrl1.EnableRefresh(true);  

  46. m_ChartCtrl2.EnableRefresh(true);  



这里我添加了n条。



QT MFC 绘图技术比较_第4张图片


5.3 动态曲线

具体可见:绘图控件第五讲——绘制动态曲线 :http://blog.csdn.net/czyt1988/article/details/20136895

以前写TeeChart画图的文章时好多人问怎么动态画图,其实所有画图控件的动态画图都一样,就是不停的画,动的只是数组,控件只负责画图,你想让图像动起来,就让数据动起来!

数据动起来涉及到数组的左右移动,很简单的一个算法而已

如有一个double数组 double pdx[100],pdy[100];

每次画图时让pdx左移一位

[cpp] view plain copy 

  1. for(int i(0);i<99;++i)  

  2. {  

  3.    pdx[i] = pdx[i+1];  

  4.    pdy[i] = pdy[i+1];  

  5. }  

  6. pdy[99] = ……需要显示的新数据……  



然后每隔0.几秒画出来,就发现动起来了





ChartCtrl提供了两种绘图函数,AddPoints和AddPoint,这两种函数在绘制动态图时会有所区别,区别见上图,上面的是AddPoints,绘图长度固定,AddPoint效果见下图,图线会不停积累。


这是我在上研究生时写的一篇文章,当时放进草稿箱里一直没发出来,今天无意看到,决定把他完成,demo代码已经找不到了,可能在我以前实验室的电脑里吧~工作后也很少用mfc了,现在偶尔用用qt过把瘾,大家如果对绘图工控有需求的话,可以使用qt的qwt控件,也比较简单,这个控件帮了我很多忙,在此向作者表示感谢,大家可以查看其源代码学习其编程思想。



下载地址:http://www.codeproject.com/Articles/14075/High-speed-Charting-Control   

csdn资源下载地址:http://download.csdn.net/detail/czyt1988/6880917


C++ GUI 绘图控件目录

MFC


  • VS2010 使用TeeChart绘图控件 - 之一 - 控件和类的导入

  • VS2010 使用TeeChart绘图控件 - 之二 - 绘制图形(折线图,柱状图)

  • TeeChart绘图控件 - 之三 - 提高绘图的效率

  • MFC下好用的高速绘图控件-(Hight-Speed Charting)

  • 绘制动态曲线


Qt


  • qt超强精美绘图控件 - QCustomPlot一览

  • qt超强绘图控件qwt - 安装及配置