本文是基于博主最近在进行的一个项目,项目要求利用MFC绘制出相应的力监测软件,在上网查阅了相关的资料之后,发现网上关于MFC中ChartCtrl绘制曲线的内容鱼龙混杂,故在此对之前学习的一些知识进行总结,希望能帮助到大家学习.
目录
MFC介绍
MFC(MicrosoftFoundationClasses)是微软基础类库的简称,是微软公司实现的一个C++类库,主要封装了大部分的windows API函数,vc++是微软公司开发的c/c++的集成开发环境,所谓集成开发环境,就是说利用它可以编辑,编译,调试,而不是使用多种工具轮换操作,灵活性较大。vc也指它的内部编译器,集成开发环境必须有一个编译器内核,例如DevC++其中一个编译器内核就是gcc。 MFC除了是一个类库以外,还是一个框架,在vc++里新建一个MFC的工程,开发环境会自动帮你产生许多文件,同时它使用了mfcxx.dll。xx是版本,它封装了mfc内核,所以你在你的代码看不到原本的SDK编程中的消息循环等等东西,因为MFC框架帮你封装好了,这样你就可以专心的考虑你程序的逻辑,而不是这些每次编程都要重复的东西,但是由于是通用框架,没有最好的针对性,当然也就丧失了一些灵活性和效率。但是MFC的封装很浅,所以效率上损失不大。
刚开始入门的同学可以参考鸡啄米老师对于MFC空间的详细介绍:
《鸡啄米 ----- VS2010/MFC编程入门教程之目录和总结》
网址如下:VS2010/MFC编程入门教程之目录和总结-软件开发-鸡啄米
利用ChartCtrl类进行绘制曲线图
在数据采集中,有的时候需要将采集数据以曲线的方式显示出来,MFC并没有提供容易使用的曲线显示控件,好在有好心人写了ChartCtrl控件,可以很方便的绘制曲线。其代码公开在CodeProject网站:High-speed Charting Control - CodeProject,大家自行下载即可,我也会把我自行绘制的动态曲线图源码贴在文中,下载不了的同学可以参考我的源码进行使用ChartCtrl类.
一.利用ChartCtrl类进行绘制静态曲线
绘制静态曲线是绘制动态曲线的基础,在此我们结合图片向大家演示如何绘制出一个静态曲线图.老版本的VC使用stdafx.h作为预编译头,VS2019使用pch.h作为预编译头,为了方便,干脆取消掉预编译头:属性->c/c+±>预编译头->不使用预编译头,如下图所示:
将ChartCtrl类里的相关文件分类导入到头文件与源文件中,并生成解决方案,查看是否存在错误.正常编译过之后,添加一个Custom Control控件,曲线控件使用Custom Control作为载体,在窗体上放置Custom Control后,需要设置stytle属性为0x52010000,将Custom Control控件的类设置为ChartCtrl,并修改其合适的ID.
为Custom Control添加一个合适的变量,在这里我们给变量起名为m_chart.注意控件类型要设置成ChartCtrl,否则有可能会出现与预期结果不一致的情况.
在刚开始需要在头文件中定义我们需要用到的一些变量,比如两条曲线以及为Botton控件添加事件处理程序:
修改MFC中OnInitDialog这个类,这个类主要是实现对基础控件的初始化,对曲线的初始化可以从以下的四部分进行介绍:
- 设置标题
- 设置坐标轴的属性
- 其他设置
- 设置曲线
在这里我们以显示北京、哈尔滨、广州三座城市的全年温度曲线图为例,向大家说明一下代码各自实现的功能:
//在这部分添加初始化后的曲线
//1.设置标题
CChartTitle* title = m_chart.GetTitle();//获取指针
title->AddString(_T("全年温度曲线图"));
title->SetColor(RGB(0, 0, 0));//设置颜色
title->SetFont(150, _T("黑体"));//设置字体
//2. 设置X轴
CChartAxis* pXAxis = m_chart.CreateStandardAxis(CChartCtrl::BottomAxis);
pXAxis->SetMinMax(1, 12);//设置极值
pXAxis->SetAutomatic(false);//设置X轴为不可缩放
//设置标题
pXAxis->GetLabel()->SetText(_T("月份"));
pXAxis->GetLabel()->SetColor(RGB(0, 0, 0));
pXAxis->GetLabel()->SetFont(140, _T("黑体"));
//设置栅格颜色
//pXAxis->GetGrid()->SetColor(RGB(255, 0, 0));
//设置颜色
//pXAxis->SetTextColor(RGB(0, 0, 255));
//设置是否可显
//pXAxis->SetVisible(false);
//3.设置Y轴
CChartAxis* pYAxis = m_chart.CreateStandardAxis(CChartCtrl::LeftAxis);
pYAxis->SetMinMax(-10, 40);//设置极值
pYAxis->SetAutomatic(false);//设置Y轴为不可缩放
//设置标题
pYAxis->GetLabel()->SetText(_T("温度(℃)"));
/*pYAxis->GetLabel()->SetColor(RGB(0, 0, 0));
pYAxis->GetLabel()->SetFont(140, _T("黑体"));*/
//设置栅格颜色
//pYAxis->GetGrid()->SetColor(RGB(255, 0, 0));
//设置颜色
//pYAxis->SetTextColor(RGB(0, 0, 255));
//设置是否可显
//pYAxis->SetVisible(false);
//4.其他设置
m_chart.GetLegend()->SetVisible(true);//设置图例显示
m_chart.SetPanEnabled(false);//设置为不可拖动
m_chart.SetZoomEnabled(false);//设置为不可缩放
//去除边框
m_chart.SetEdgeType(0);
//5.设置曲线
//创建曲线
m_pLineSerie = m_chart.CreateLineSerie();
m_pLineSerie2 = m_chart.CreateLineSerie();
//设置宽度
m_pLineSerie->SetWidth(2);
m_pLineSerie2->SetWidth(2);
//设置颜色
//曲线1为红色
m_pLineSerie->SetColor(RGB(255, 0, 0));
//曲线2为蓝色
m_pLineSerie2->SetColor(RGB(0, 0, 255));
//设置阴影
m_pLineSerie->EnableShadow(true);
m_pLineSerie2->EnableShadow(true);
//图例曲线含义
m_pLineSerie->SetName(_T("日均最高气温"));
m_pLineSerie2->SetName(_T("日均最低气温"));
//默认显示北京温度
OnBnClickedButtonBeijing();
为Botton1、Botton2、Botton3分贝添加事件处理程序用于显示北京、哈尔滨、广州的全年温度曲线.因为是温度曲线图,所以X轴输入月份,Y轴输入温度,两条曲线分别最高和最低的温度曲线.
void CStaticLine2Dlg::OnBnClickedButtonBeijing()
{
// TODO: 在此添加控件通知处理程序代码
//清除标题
m_chart.GetTitle()->RemoveAll();
//设置标题
m_chart.GetTitle()->AddString(_T("北京-全年温度曲线图"));
//清除数据
m_pLineSerie->ClearSerie();
m_pLineSerie2->ClearSerie();
//X轴数据
double xMonth[12] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//Y轴极值
m_chart.GetLeftAxis()->SetMinMax(-10, 40);
//最高温度值
double highTemp[12] = { 1,3,10,18,28,34,38,35,26,17,10,3 };
//最低温度值
double lowTemp[12] = { -6,-4,3,10,12,23,23,16,10,6,2,-1 };
//绘制曲线
m_pLineSerie->AddPoints(xMonth, highTemp, 12);
m_pLineSerie2->AddPoints(xMonth, lowTemp, 12);
}
静态曲线绘制结果如下所示,图中数据并未经过官方考核,仅用于显示温度曲线,与实际情况存在偏差.
二.利用ChartCtrl类进行绘制动态曲线
动态曲线图和静态曲线图在基础属性设置上基本一致,本文以"实时力监测软件"为例,进行说明动态曲线图的绘制.力监测软件的初始界面如下:
因为整个监测软件采用Modbus TCP协议进行传输数据,因此需要输入相应的IP地址和对应的端口号,并点击"开始采集"按钮,右侧Custom Control自定义控件显示六十组相关数据,当超过六十组数据,X轴进行自更新,显示后续的数据.右上角进行显示力控法兰的实时受力数据.
对于MFC中OnInitDialog类,将原来静态曲线图中的两条曲线修改成一条曲线,其余部分变动不大,在此就不进行过多介绍.
动态曲线图的绘制关键在于MFC中的定时器Timer,相应的函数类型有SetTimer和KillTimer等.
SetTimer相关参数的介绍:
第一个参数代表定时器的代号,以0、1、2等数字进行表示,第二个参数代表每次间隔的毫秒数,第三个参数可以设置成NULL即可.为"开始采集"按钮添加事件处理程序并启动定时器程序.
void CStaticLine2Dlg::OnTimer(UINT_PTR nIDEvent)
{
//清空曲线
m_pLineSerie->ClearSerie();
//初始化定义m_Tick参数
m_Tick++;
if (m_Tick <= 60)
{
//X轴范围[0-60]
m_chart.GetBottomAxis()->SetMinMax(0, 60);
m_chart.GetBottomAxis()->SetAutomatic(false);//不可缩放
//Y轴范围[0-2000]
m_chart.GetLeftAxis()->SetMinMax(0, 2000);
//输入X轴数据
for (int i = 0; i < m_Tick; i++)
{
m_XSecond[i] = i;
}
//输入Y轴数据
if (m_Tick == 1)
{
m_YTemperature[0] = 0;
}
else
{
number= rand() % 100 + 1000;
m_YTemperature[m_Tick - 1] = number;
//实时力控显示
SetDlgItemInt(IDC_EDIT_POWER, number);
}
}
else
{
//设置X轴可缩放
m_chart.GetBottomAxis()->SetAutomatic(true);
//Y轴范围
m_chart.GetLeftAxis()->SetMinMax(0, 2000);
//X轴数据更迭
for (int i = 1; i < 60; i++)
{
//覆盖数据
m_XSecond[i - 1] = m_XSecond[i];
}
//填充新数据
m_XSecond[59] = m_Tick;
//Y轴数据更迭
for (int i = 1; i < 60; i++)
{
m_YTemperature[i - 1] = m_YTemperature[i];
}
m_YTemperature[59] = rand() % 100 + 1000;
SetDlgItemInt(IDC_EDIT_POWER, m_YTemperature[59]);
}
//绘制曲线
if (m_Tick >= 60)
{
//绘制60个点
m_pLineSerie->AddPoints(m_XSecond, m_YTemperature, 60);
}
else
{
//绘制m_Tick个点
m_pLineSerie->AddPoints(m_XSecond, m_YTemperature, m_Tick);
}
CDialogEx::OnTimer(nIDEvent);
}
绘制完成之后,点击"停止采集"按钮,关闭定时器程序.程序运行示意图如下:
前六十组数据采集:
后续数据采集:
程序源码
如需程序源码,请移步Gittee:MFC: MFC静态曲线和动态曲线绘制