其中涉及到MFC和实时曲线显示的问题由于我之前从未接.docx
《其中涉及到MFC和实时曲线显示的问题由于我之前从未接.docx》由会员分享,可在线阅读,更多相关《其中涉及到MFC和实时曲线显示的问题由于我之前从未接.docx(15页珍藏版)》请在冰豆网上搜索。
其中涉及到MFC和实时曲线显示的问题由于我之前从未接
最近接手了一个项目,其中涉及到MFC和实时曲线显示的问题,由于我之前从未接触过此类技术,现学现搞,把其间用到的觉得对初学者有用的东西,总结一下。
尤其是关于TeeChart控件部分,网上资料零碎,且很多不全面,代码难以使用。
我苦寻数周在外国一些网站上寻到了一些有用的信息,把相关的可运行的代码示例贴在文中,希望能帮到后来者。
//我的博客:
MFC部分:
一、
分割窗体
新建一个单文档的MFC工程(注意在向导中设置窗口最大化和分割窗口支持)。
新建两个对话框,用于分割窗口
【注意】对话框的样式(Style)属性改为下层(Child),边框(Border)属性改为None,最开始没有改这个,程序运行的时候报错了。
【注意】将两个对话框生成从CFormView派生的类。
在CMainFrame的OnCreateClient中添加
【例1】把框架分割成两列,右边的一列和对话框绑定。
m_SplitterWnd.CreateStatic(this,1,2));//把此框架窗口分割成1行2列。
m_SplitterWnd.SetColumnInfo(0,200,0);//设置第0列的最大宽度为200,最小宽度为0(此句话非常重要)
CRectrect;
GetClientRect(&rect);
//第1行第1列的窗口与CMyView绑定。
其宽度为框架宽度的3/4.高度与框架的高度一致
if(!
m_SplitterWnd.CreateView(0,0,RUNTIME_CLASS(CMyView),CSize(rect.Width()/4*3,rect.Height()),pContext)||
//第1行第2列的窗口与我们的对话框CMyDlg绑定。
其宽度为框架宽度的1/4.
!
m_SplitterWnd.CreateView(0,1,RUNTIME_CLASS(CMyDlg),
CSize(rect.Width()/4,rect.Height()),pContext))
{
returnFALSE;
}
returnTRUE;
【例2】在分割后的子窗口上继续分割
在CMainFrame中添加两个成员变量,类型为CSplitterWnd,如下所示
CSplitterWndm_splitterWnd1;
CSplitterWndm_splitterWnd2;
添加虚函数virtualBOOLOnCreateClient(LPCREATESTRUCTlpcs,CCreateContext*pContext);
程序代码修改部分如下:
BOOLCMainFrame:
:
OnCreateClient(LPCREATESTRUCTlpcs,CCreateContext*pContext)
{
//创建一个静态分栏窗口,分为一行二列
if(m_splitterWnd1.CreateStatic(this,1,2)==NULL)
returnFALSE;
//设置分割窗口的大小***
m_splitterWnd1.SetColumnInfo(0,200,0);//设置第0列的最大宽度为200,最小宽度为0
//将CCSplitterWndView连接到0行0列窗格上
m_splitterWnd1.CreateView(0,0,RUNTIME_CLASS(CsplitterwndView),CSize(600,500),pContext);
//将第0行1列再分开2行1列
if(m_splitterWnd2.CreateStatic(&m_splitterWnd1,2,1,WS_CHILD|WS_VISIBLE,
m_splitterWnd1.IdFromRowCol(0,1))==NULL)
returnFALSE;
//将FormView1类连接到第二个分栏对象的0行0列
m_splitterWnd2.CreateView(0,0,RUNTIME_CLASS(CForm1),CSize(0,300),pContext);//因为是上下分割,故系统不关注宽度,只看高度,故宽度可以为0
//将FormView2类连接到第二个分栏对象的1行0列
m_splitterWnd2.CreateView(1,0,RUNTIME_CLASS(CForm2),CSize(0,0),pContext);//此高度为0,意为分割后剩下的高度就是它的了。
returnTRUE;
}
//CsplitterwndView、CForm1、CForm2都是我们自定义的类,可以把他们换成对话框或表单等。
//初始左右分割框架,要调用函数SetColumnInfo来设定分割线位置
对分割出来的一列再进行分割,则是由CreateView中CSize的高度来确定分割线位置
*总结:
*给框架窗口添加静态拆分视图的过程如下:
*1.给框架窗口类添加一个CsplitterWnd数据成员。
*2.覆盖框架窗口的OnCreateClient函数,并调用CsplitterWnd:
:
CreateStatic来创建静态拆分视图。
*3.使用CsplitterWnd:
:
CreateView在每个静态拆分窗口的窗格中创建视图
*使用静态拆分窗口的一个优点是由于您自己给窗格添加视图,所以可以控制放入视图的种类
二、
添加自定义消息响应
1、在Resource.h中添加
#defineWM_MY_MESSAGE(WM_USER+100)
2、在CMyView的定义中添加:
//CMyView是要响应自定义消息的我们的视图类
//{{AFX_MSG(CMyView)
afx_msgLRESULTOnMyMsg(WPARAM,LPARAM);
DECLARE_MESSAGE_MAP()
//}}AFX_MSG
3、在CMyView的实现cpp文件中添加
BEGIN_MESSAGE_MAP(CMyView,CFormView)
//{{AFX_MSG_MAP(CMyView)
ON_MESSAGE(WM_MY_MESSAGE,OnMyMsg)//添加消息映射
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
4、实现消息映射函数LRESULTCMyView:
:
OnMyMsg(WPARAMwParam,LPARAMlParam)
发送消息,触发消息响应函数
((ViewPoints*)p)->pMyView->PostMessage(WM_MY_MESSAGE,0,0);
//CTSDoc*pDoc=(CTSDoc*)(((ViewPoints*)p)->pTeeFFTSIGView->GetDocument());
//pDoc->clientData=_T(buff);
TeeChart部分:
(以VC++6.0TeeChart8.0为例)
至于如何获取TeeChart控件,如何注册控件,请XX之,网上有很多。
零
在相应的源文件中添加TeeChart的头文件(有需要的自己再添加)
#include"tchart.h"
#include"series.h"
#include"valuelist.h"
#include"axes.h"
#include"axis.h"
#include"pen.h"
#include"axislabels.h"
#include"teefont.h"
#include"axistitle.h"
#include"aspect.h"
#include"fastlineseries.h"
#include"titles.h"
#include"fastlineseries.h"
#include"panel.h"
#include"legend.h"
#include"annotationtool.h"
#include"page.h"
#include"strings.h"
#include"gradient.h"
#include"IsoSurfaceSeries.h"
一、
在视图类中动态添加TeeChart控件。
(解决手工拖动添加控件,编译报”DebugAssertionFailed”错的问题)
我们添加对话框资源让其继承自CFromView。
首先手工静态把控件拖到对话框上,然后建立类向导,生成一个对象m_chart。
在主框架CMainFrame:
:
OnCreateClient()或OnCreate()中【看在哪个函数中分割窗口产生视图】
RecalcLayout();//这一句很重要,没有它,会报错。
pView->OnInitialUpdate();//pView是我们分割窗口得到的CMyDlgView视图的指针。
在视图类CMyDlgView中添加OnInitialUpdate()函数
CRectrect;
GetClientRect(&rect);
m_chart.MoveWindow(&rect,TRUE);
在视图类CMyDlgView中添加WM_CREATE消息响应函数OnCreate()在其中添加
m_chart.Create("",WS_VISIBLE,CRect(0,0,0,0),this,1234);//动态生成控件
m_chart.AddSeries(0);//操作控件
m_chart.Series(0).FillSampleValues(50);
//m_chart是我们的控件TeeChart
即可。
//但此为动态添加的控件,所有设置操作都得通过代码操作。
二、
绘制2D曲线
这个在网上有很多资料了。
我在这里再简单总结一下其过程。
A、初始化部分:
在TeeChart控件所在的视图类的OnCreate函数中,进行TeeChart控件的初始化工作。
m_chart.Create("",WS_VISIBLE,CRect(0,0,0,0),this,1234);//动态创建TeeChart控件
m_chart.GetLegend().SetVisible(false);//隐藏图例
m_chart.GetAspect().SetView3D(FALSE);//取消3D显示
//设置图标标题
m_chart.GetHeader().GetText().SetItem(0,COleVariant("传感器实时数据曲线"));
//设置纵轴标题
m_chart.GetAxis().GetLeft().GetTitle().SetCaption("数值");
//设置渐变背景
m_chart.GetPanel().GetGradient().SetVisible(true);
m_chart.GetPanel().GetGradient().SetStartColor(RGB(192,192,192));
m_chart.GetPanel().GetGradient().SetEndColor(RGB(255,255,255));
//添加曲线
m_chart.AddSeries(0);
//设置曲线属性
m_chart.Series(0).SetColor(RGB(255,0,0));//颜色
m_chart.Series(0).GetAsLine().GetLinePen().SetWidth
(2);//线型宽度
//设置x轴的取值范围
m_chart.GetAxis().GetBottom().SetMinMax(0,100);
//设置x轴上值的格式
m_chart.GetAxis().GetBottom().GetLabels().SetValueFormat("0.0");
B、绘制部分:
在TeeChart控件所在的视图类的自定义消息响应函数OnMyMsg中,或是在定时器中,添加:
COleDateTimeCurTime=COleDateTime:
:
GetCurrentTime();
COleDateTimeSpantmSpan=COleDateTimeSpan(0,0,1,0);//1s
CStringcsTime;
csTime=CurTime.Format("%H:
%M:
%S");//获取当前时间
//在CMyView中画曲线
m_chart.Series(0).Add(yVal,csTime,RGB(255,0,0));//第一个参数是y轴值,第二个参数是对应的x轴的标签值(此为当前时间字符串),第三个参数是所绘点的颜色。
CurTime+=tmSpan;
m_chart.Series(0).RefreshSeries();
if(m_chart.Series(0).GetCount()>100)
{
m_chart.GetAxis().GetBottom().Scroll(1.0,true);//x坐标轴一次移动1格
}
由于TeeChart绘制曲线点的函数Add,每调用一次才绘制一次,故需要有外部消息激发消息响应函数,才能把曲线动态绘制出来。
可以用设置定时器和自定义消息响应函数的方式来实现。
(定时器比较简单,消息响应函数上面MFC部分已经讲过)
三、
绘制3D曲线
解决TeeChart8中绘制3D图形报”Invalid class typecast”错的问题。
A、在承载TeeChart的对话框类Dlg的类定义中,添加:
VARIANTSeriesIndex;
B、在类的相关方法中绘制,添加代码:
m_chart.RemoveAllSeries();
//下面的设置很重要(没有的话,会出错)
SeriesIndex.vt=VT_INT;
SeriesIndex.intVal=m_chart.AddSeries(scWaterfall);//scWaterfall=33瀑布图的编号
m_chart.Series(0).GetAsWaterfall().SetIrregularGrid(true);
m_chart.Series(0).GetAsWaterfall().AddXYZ(x,y,z,NULL,RGB(255,0,0));
(TeeChart的3D图有很多种,上面是以瀑布图为例的,其他图种的编号如下:
)
constunsignedlongscLine=0;
constunsignedlongscBar=1;
constunsignedlongscHorizBar=2;
constunsignedlongscArea=3;
constunsignedlongscPoint=4;
constunsignedlongscPie=5;
constunsignedlongscFastLine=6;
constunsignedlongscShape=7;
constunsignedlongscGantt=8;
constunsignedlongscBubble=9;
constunsignedlongscArrow=10;
constunsignedlongscCandle=11;
constunsignedlongscPolar=12;
constunsignedlongscSurface=13;
constunsignedlongscVolume=14;
constunsignedlongscErrorBar=15;
constunsignedlongscBezier=16;
constunsignedlongscContour=17;
constunsignedlongscError=18;
constunsignedlongscPoint3D=19;
constunsignedlongscRadar=20;
constunsignedlongscClock=21;
constunsignedlongscWindRose=22;
constunsignedlongscBar3D=23;
constunsignedlongscImageBar=24;
constunsignedlongscDonut=25;
constunsignedlongscTriSurface=26;
constunsignedlongscBox=27;
constunsignedlongscHorizBox=28;
constunsignedlongscHistogram=29;
constunsignedlongscColorGrid=30;
constunsignedlongscBarJoin=31;
constunsignedlongscHighLow=32;
constunsignedlongscWaterfall=33;
constunsignedlongscSmith=34;
constunsignedlongscPyramid=35;
constunsignedlongscMap=36;
constunsignedlongscHorizLine=37;
constunsignedlongscFunnel=38;
constunsignedlongscCalendar=39;
constunsignedlongscHorizArea=40;
constunsignedlongscPointFigure=41;
constunsignedlongscGauge=42;
constunsignedlongscVector3D=43;
constunsignedlongscTower=44;
constunsignedlongscPolarBar=45;
constunsignedlongscBubble3D=46;
constunsignedlongscHorizHistogram=47;
constunsignedlongscVolumePipe=48;
constunsignedlongscIsoSurface=49;
constunsignedlongscDarvas=50;
constunsignedlongscHighLowLine=51;
constunsignedlongscPolarGrid=52;
constunsignedlongscDeltaPoint=53;
constunsignedlongscImagePoint=54;
constunsignedlongscOrganizational=55;
constunsignedlongscWorld=56;
constunsignedlongscTagCloud=57;
constunsignedlongscKagi=58;
constunsignedlongscRenko=59;
constunsignedlongscNumericGauge=60;
constunsignedlongscLinearGauge=61;
constunsignedlongscCircularGauge=62;
constunsignedlongscBigCandle=63;
constunsignedlongscLinePoint=64;
//如需要相关图种,只需把上面代码
SeriesIndex.intVal=m_chart.AddSeries(scWaterfall);//把scWaterfall改为你所需图种的编号
m_chart.Series(0).GetAsWaterfall().SetIrregularGrid(true);//GetAsWaterfall改为你所需图种的相关函数名
----------------
一个完整的例子:
A、在CMyView(承载TeeChart的对话框视图)的定义中,添加VARIANTSeriesIndex;
B、在intCMyView:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)函数中:
intCMyView:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(CFormView:
:
OnCreate(lpCreateStruct)==-1)
return-1;
//TODO:
Addyourspecializedcreationcodehere
m_chart.Create("",WS_VISIBLE,CRect(0,0,0,0),this,1234);
m_chart.GetLegend().SetVisible(false);//隐藏图例
m_chart.GetAspect().SetView3D(true);//3D显示
m_chart.GetAxis().GetDepth().SetVisible(TRUE);//显示Z轴
m_chart.GetAxis().GetDepth().GetLabels().SetVisible(TRUE);//显示Z轴上的坐标
m_chart.GetAxis().GetDepth().GetLabels().SetStyle(0);//设置显示坐标的风格
//设置渐变背景
m_chart.GetPanel().GetGradient().SetVisible(true);
m_chart.GetPanel().GetGradient().SetStartColor(RGB(192,192,192));
m_chart.GetPanel().GetGradient().SetEndColor(RGB(255,255,255));
//设置图标标题
m_chart.GetHeader().GetText().SetItem(0,COleVariant("瀑布图"));
//开始绘制3D
m_chart.RemoveAllSeries();
SeriesIndex.vt=VT_INT;
SeriesIndex.intVal=m_cha