您好,欢迎来到筏尚旅游网。
搜索
您的当前位置:首页用Chart控件绘制动态图表

用Chart控件绘制动态图表

来源:筏尚旅游网


用Chart控件绘制动态图表

---- 进行程序设计时,选用一个合适的ActiveX控件,有时可大大减少编程工作量。ActiveX 控件(又称OCX)基于COM技术,作为的软件模块,它可以在任何程序设计语言 中插入使用。本文仅以VC++为例说明Chart控件的使用。

---- Chart控件指Mschart.ocx(5.0版)或Mschrt20.ocx(6.0 版),是Visual Studio自带的ActiveX控件之一,其属性、事件很多,功能非常强大,可 实现柱状直方图、曲线走势图、饼状比例图等,甚至可以是混合图表,可以是二维或三 维图表,可以带或不带坐标系,可以自由配置各条目的颜色、字体等等。

一 安装和使用Chart控件

----在用到Chart控件的项目中安装该控件:从Project->Add to Project->Components And Controls->Registered Active Xcontrols,选择Chart控件,则 ClassWizard会生成相应的C++类,其中类CMSChart是由CWnd派生来的,它是Chart 控件的主要类,其他的类全部是由COleDispatchDriver派生来,控制控件中的相应对象, 完成各部分相关功能,如CvcAxis类是实现坐标轴相关功能的源代码。同时在项目的控件 工具箱上会出现代表Chart控件的按钮,使用时把Chart控件按钮从工具箱拖到对话框中, 调整大小即可。

----Chart控件至少有45个属性、9个方法、49个事件,在这 里就不一一列举了。

---- 在设计中,我们可以在主要属性页里修改各属性的属性 值:右击对话框窗口中的Chart控件,选择“Properties”菜单项,就会弹出主要属性页对 话框,对其中各

属性值进行设置。有些属性在主要属性页里没有列出,只能编程修改。 另外要动态绘制图表,必须掌握对控件的编程控制。

---- 首先在对话框类中定义控件变量,以便编程时操纵控件。 如对话框类定义如下:

class CAbcDlg : public CDialog{

public:

CAbcDlg(CWnd* pParent = NULL);

//{{AFX_DATA(CAbcDlg)

enum { IDD = IDD_ABC_DIALOG };

CMSChart m_Chart;

//}}AFX_DATA

......

};

----ActiveX控件的属性和方法在控件内部对应唯一一个整数 索引值,编程时可以通过索引来设置或获取控件的属性值,也可以通过调用控件的C+ +类(在这里就是

CMSChart)的成员函数设置或获取控件的属性值及调用控件的方法。 例如:

----在CMSChart类实现中有如下代码:

CString CMSChart::GetData(){

CString result;

InvokeHelper(0x9, DISPATCH_PROPERTYGET,

VT_BSTR, (void*)&result, NULL);

return result;

}

void CMSChart::SetData(LPCTSTR lpszNewValue){

static BYTE parms[] =VTS_BSTR;

InvokeHelper(0x9, DISPATCH_PROPERTYPUT,

VT_EMPTY, NULL, parms,lpszNewValue);

}

void CMSChart::Refresh(){

InvokeHelper(DISPID_REFRESH,

DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

}

----这段代码表明:属性“Data”索引值为0x9,我们可以调 用函数SetData对图表中某点的值进行设置。索引值为DISPID_REFRESH的方法 “Refresh”,调用它进行刷新。如:

CString str=“34.5\";

m_Chart.SetData(str);

m_Chart.Refresh();

......

----阅读CMSChart类的实现会发现,有些属性的值不是普通 的BOOL、CString等数据类型,而是另一个控件驱动类的类变量,如:

CVcPlot CMSChart::GetPlot(){

LPDISPATCH pDispatch;

InvokeHelper(0x28, DISPATCH_PROPERTYGET,

VT_DISPATCH, (void*)&pDispatch, NULL);

return CVcPlot(pDispatch);

}

----在CVcPlot类的实现中有如下代码:

CVcAxis CVcPlot::GetAxis

(long axisID, const VARIANT& Index){

LPDISPATCH pDispatch;

static BYTE parms[] =VTS_I4 VTS_VARIANT; InvokeHelper(0x1f, DISPATCH_PROPERTYGET,

VT_DISPATCH, (void*)&pDispatch, parms, axisID, return CVcAxis(pDispatch);

}

Index);

----而CVcAxis类的实现中有如下代码:

CVcValueScale CVcAxis::GetValueScale(){

LPDISPATCH pDispatch;

InvokeHelper(0x9, DISPATCH_PROPERTYGET,

VT_DISPATCH, (void*)&pDispatch, NULL);

return CVcValueScale(pDispatch);

}

----而CVcValueScale类的实现中又有如下代码:

void CVcValueScale::SetMaximum(double newValue){

static BYTE parms[] =VTS_R8;

InvokeHelper(0x3, DISPATCH_PROPERTYPUT,

VT_EMPTY, NULL, parms,newValue);

}

----这正是Chart控件的灵活性所在,根据上述代码,如下的 调用:

VARIANT var;

m_Chart.GetPlot().GetAxis(1, var).GetValueScale()

.SetMaximum(50.0);

可实现把纵坐标的最大刻度设为50.0。

----控件触发的事件,如Click、MouseDown等,如果需要处 理,可以通过ClassWizard在对话框类中定义相应的处理函数,实现相关的处理功能。

二 动态绘制图表实例

---- 在一个温度采集系统中,希望把采集来的各项温度值 实时显示,用Chart控件绘制曲线走势图:

各温度项以不同颜色的曲线表示;

横坐标为时间,纵坐标为温度值,均要求滚动显示;

在每次采样完成后,刷新屏幕。

----设计思路

随着时间的推移,采集来的数据不断增加,不一定在一屏中显示,所以系统打开 一个实时数据库,存放采集来的实时数据。显示时,需要哪个时间段的数据,就从数据 库中读取。

在对话框资源编辑时,增加水平滚动条和垂直滚动条,以便配合Chart控件进行滚动 显示。

为对话框启动定时器,按采样间隔进行采样,并刷新屏幕显示。

----主要相关代码如下:

BOOL CAbcDlg::OnInitDialog(){

CDialog::OnInitDialog();

pDataDB = new dbase;

//实时数据记录库,类dbase的基类为CDaoRecordset

pDataDB->Open(dbOpenDynaset, “select

* from data\");

VARIANT var;

m_Chart.GetPlot().GetAxis(1,var).GetValueScale().

SetAuto(FALSE);//不自动标注y轴刻度

m_Chart.GetPlot().GetAxis(1, var).GetValueScale().

SetMaximum(37);//y轴最大刻度

m_Chart.GetPlot().GetAxis(1, var).GetValueScale().

SetMinimum(32);//y轴最小刻度

m_Chart.GetPlot().GetAxis(1,var).GetValueScale().

SetMajorDivision(5);//y轴刻度5等分

m_Chart.GetPlot().GetAxis(1,var).GetValueScale().

SetMinorDivision(1);//每刻度一个刻度线

m_Chart.SetColumnCount(3); //3个温度项,3条曲线

m_Chart.GetPlot().GetSeriesCollection().GetItem(1).

GetPen().GetVtColor().Set(0, 0, 255);//线色

m_Chart.GetPlot().GetSeriesCollection().GetItem(2).

GetPen().GetVtColor().Set(255, 0, 0);

m_Chart.GetPlot().GetSeriesCollection().GetItem(3).

GetPen().GetVtColor().Set(0, 255, 0);

m_Chart.GetPlot().GetSeriesCollection().

GetItem(1).GetPen().SetWidth(2);//线宽

m_Chart.GetPlot().GetSeriesCollection().

GetItem(2).GetPen().SetWidth(2);

m_Chart.GetPlot().GetSeriesCollection().

GetItem(3).GetPen().SetWidth(2);

m_Chart.SetRowCount(10); //一屏显示10个采样时刻

m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale().

SetAuto(FALSE);//不自动标注x轴刻度

m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale().

SetDivisionsPerLabel(1);//每时刻一个标注

m_Chart.GetPlot().GetAxis(0,var).GetCategoryScale().

SetDivisionsPerTick(1);//每时刻一个刻度线

m_ScrLeft.SetScrollRange(0,45);

//垂直滚动条可滚动范围(温度值范围0-50,

每滚动1度,一屏显示5度)

m_ScrLeft.SetScrollPos(45-32);//垂直滚动条的当前位置

m_ScrBottom.SetScrollRange(0, 0);//水平滚动条的可滚动范围

m_ScrBottom.SetScrollPos(0);//水平滚动条的当前位置

SetTimer(23, 300000, NULL);//启动定时器,定时间隔5分钟

Sample();//调用采样函数进行第一次采样,并把数据记录入库

return TRUE;

}

void CAbcDlg::OnTimer(UINT nIDEvent) {

Sample();//采样,并把数据记录入库

if (pDataDB->GetRecordCount()>10)

theApp.nBottomRange = pDataDB->GetRecordCount()-10;

else

theApp.nBottomRange = 0;

//用全局变量保存水平滚动条的范围值

m_ScrBottom.SetScrollRange(0,theApp.nBottomRange);

theApp.nBottomPos = theApp.nBottomRange;

m_ScrBottom.SetScrollPos(theApp.nBottomPos);

//修正水平滚动条的显示

DrawPic();//调用函数,刷新曲线显示

CDialog::OnTimer(nIDEvent);

}

void CAbcDlg::DrawPic() {

char s[10];

UINT row = 1;

pDataDB->MoveFirst();

pDataDB->Move(theApp.nBottomPos);

//只从数据库中取某时间段的数据进行显示

while ((!pDataDB->IsEOF()) && (row m_Chart.SetRow(row);

m_Chart.SetRowLabel((LPCTSTR)pDataDB

->m_date_time.Format(“%H:%M\"));

//以采样时刻做x轴的标注

10)){ <=

m_Chart.SetColumn(1);

sprintf(s, “%6.2f\pDataDB->m_No1);

m_Chart.SetData((LPCSTR)s);

m_Chart.SetColumn(2);

sprintf(s, “%6.2f\pDataDB->m_No2);

m_Chart.SetData((LPCSTR)s);

m_Chart.SetColumn(3);

sprintf(s, “%6.2f\pDataDB->m_No3);

m_Chart.SetData((LPCSTR)s);

pDataDB->MoveNext();

row++;

}

while ((row <= 10)){

m_Chart.SetRow(row);

m_Chart.SetRowLabel((LPCTSTR)“\");

m_Chart.GetDataGrid().SetData(row, 1, 0, 1);

//采样数据不足10个点, 对应的位置不显示

m_Chart.GetDataGrid().SetData(row, 2, m_Chart.GetDataGrid().SetData(row, 3, row++;

}

m_Chart.Refresh();

}

void CAbcDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) if (pDataDB->GetRecordCount()>10) 0, 1); 0, 1);

{

theApp.nBottomRange = pDataDB->GetRecordCount()-10;

else

theApp.nBottomRange = 0;

m_ScrBottom.SetScrollRange(0, theApp.nBottomRange);

switch (nSBCode){

case SB_LINERIGHT:

if (theApp.nBottomPos < theApp.nBottomRange){

theApp.nBottomPos = theApp.nBottomPos + 1;

m_ScrBottom.SetScrollPos(theApp.nBottomPos);

DrawPic();

}

break;

case SB_LINELEFT:

if (theApp.nBottomPos > 0){

theApp.nBottomPos = theApp.nBottomPos - 1;

m_ScrBottom.SetScrollPos(theApp.nBottomPos);

DrawPic();

}

break;

}

CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

}

void CAbcDlg::OnVScroll(UINT nSBCode,

UINT nPos, CScrollBar* pScrollBar) {

VARIANT var;

double max1,min1,f;

switch (nSBCode){

case SB_LINEDOWN:

f = m_Chart.GetPlot().GetAxis(1, var).

GetValueScale().GetMinimum() - 1;

if (f>=0) {//最小刻度大于等于0, 则可以滚动

m_Chart.GetPlot().GetAxis(1, var).GetValueScale().

SetMinimum(f);

f = m_Chart.GetPlot().GetAxis

(1, var).GetValueScale().GetMaximum() - 1;

m_Chart.GetPlot().GetAxis(1, var).GetValueScale().

SetMaximum(f);

pScrollBar->SetScrollPos(pScrollBar->GetScrollPos() m_Chart.Refresh();

1); +

}

break;

case SB_LINEUP:

f = m_Chart.GetPlot().GetAxis(1, var).

GetValueScale().GetMaximum() + 1;

if (f <= 50) {//最大刻度小于等于50, 则可以滚动 m_Chart.GetPlot().GetAxis

(1, var).GetValueScale().SetMaximum(f);

f = m_Chart.GetPlot().GetAxis(1, var).

GetValueScale().GetMinimum() + 1;

m_Chart.GetPlot().GetAxis(1, var).GetValueScale().

SetMinimum(f);

pScrollBar->SetScrollPos(pScrollBar->GetScrollPos() -

1);

m_Chart.Refresh();

}

break;

}

CDialog::OnVScroll(nSBCode, nPos, pScrollBar);

}

----特别注意,程序中用到的关于控件的类,如CVcAxis等, 需要在AbcDlg.cpp文件的开始处说明:#include “VcAxis.h\"。

----限于篇幅,文中仅仅是一个简单示例的部分代码。在实际 应用中,一般会有更多的需求,比如:对坐标轴进行缩放显示;采样有可能得不到正确 的采样值时曲线显示不连续等等,这时需要根据需求编写相应代码。

Passing an Array of Values to the Visual C++ MSChart OCX

Great step-by-step instructions to passing data to the VC++ MSChart component

Published July 27, 2000

By JL Colson

Step 1 : Creating the Project

Start Visual C++ en create a simple dialog based application labelled \"Graph\"

Step 2 : Add the MSChart OCX to Your Project

Select \"project menu\" option and select \"Components and contols\" and then choose the MSChart component and click \"add.\"

Step 3 : Add the MSChart OCX to Your Dialog

Select resources view tab and open the main dialog. (It抯 a simple dialog-based application). Drop the ocx on your dialog .

Now, label your Chart \"IDC_MSCAHRT1\"

Now, choose menu option \" Classwizard \" to create a member variable of your chart labelled \"m_Chart\"

Step 4: Add the Code

Now add a button labeled \"Go\" to your dialog. Double-click i

t to edit the code and add the following code in the On_Go function:

COleSafeArray saRet;

DWORD numElements[] = {10, 10}; // 10x10

saRet.Create(VT_R8, 2, numElements);

long index[2];

for(index[0]=0; index[0]<10; index[0]++) {

for(index[1]=0; index[1]<10; index[1]++) {

double val = index[0] + index[1]*10;

saRet.PutElement(index, &val);

}

}

m_Chart.SetChartData(saRet.Detach());

m_Chart.Refresh;

Step 5: Building and Running the Application

Build and execute your app, then click the \"Go\" button. Here is the result

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- efsc.cn 版权所有 赣ICP备2024042792号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务