SOS!!!绘制实时曲线
我写了一个基于对话框的画图函数,现在想测试它是否正确?哪位仁兄愿意帮忙,不胜感激!说明如下:
1.由于我把画实时曲线的过程分为两部分完成,一部分是画坐标系(只需执行一次),另一部分是根据每次采集的数据,实时画曲线(需要反复执行);所以我写了两个函数:void CPlotDemoDlg::DrawCoordinates()和void CPlotDemoDlg::DrawCurve(int AD,CTime T);
2.由于实时曲线上的数据是动态采集的,故这里我用int AD = 200-rand()%90和CTime T = CTime::GetCurrentTime()来模拟数据采集值;
3.实时曲线的绘制过程(分三个时间段:600s/60min/12h):从原点开始,依次向右画曲线;当到达600s时,清空画图区域,并重绘前600s曲线(由于换成60min的时间范围,相当于把前600秒横向压缩),再从600s依次向右画曲线;当到达60min时,清空画图区域,重绘前60min曲线,再从60min依次向右画曲线;
注:一般的实时曲线绘制程序都是从右端开始,依次向左画曲线,当曲线画满一屏时,将曲线向左推移;但我这里是要将整个监控过程都记录下来,所以需要压缩重绘。
因程序需求,我创建了一个CPublic类来保存全局变量:
Public.h
class CPublic
{
public:
CPublic();
virtual ~CPublic();
// x和y轴的长度
static int Lx;
static int Ly;
// x和y轴的格数
static int nx;
static int ny;
static int i; // 600s内,实时数据的个数
static int j; // 60min内,实时数据的个数
static int k;
};
Public.cpp:
……
int CPublic::Lx = 600+30+60+30;
int CPublic::Ly = 400+30+30+20;
int CPublic::nx = 12;
int CPublic::ny = 10;
int CPublic::i = 0;
int CPublic::j = 0;
int CPublic::k = 0;
……
下面是函数void CPlotDemoDlg::DrawCoordinates()和void CPlotDemoDlg::DrawCurve(int AD,CTime T)的源代码:
void CPlotDemoDlg::DrawCoordinates()
{
CPaintDC dc(this); // device context for painting
int n;
CString str;
// 创建画笔对象
CPen* pPenBlue = new CPen;
pPenBlue->CreatePen(PS_DOT,1,RGB(0,0,255)); // 蓝色画笔
CPen* pPenBlack = new CPen;
pPenBlack->CreatePen(PS_SOLID,1,RGB(0,0,0)); // 黑色画笔
dc.Rectangle(0,0,CPublic::Lx,CPublic::Ly);
// 建立坐标系,并保存当前画笔
CGdiObject* pOldPen = dc.SelectObject(pPenBlack);
dc.MoveTo(30,20);
dc.LineTo(30,CPublic::Ly-30);
dc.LineTo(CPublic::Lx-30,CPublic::Ly-30);
// 绘制坐标箭头
dc.MoveTo(27,30);
dc.LineTo(30,20);
dc.LineTo(33,30);
dc.MoveTo(CPublic::Lx-30-10,CPublic::Ly-30-3);
dc.LineTo(CPublic::Lx-30,CPublic::Ly-30);
dc.LineTo(CPublic::Lx-30-10,CPublic::Ly-30+3);
// 添加网格线
dc.SelectObject(pPenBlue);
for (n=1;n<=CPublic::ny;n++)
{
dc.MoveTo(30,CPublic::Ly-30-n*40);
dc.LineTo(CPublic::Lx-90,CPublic::Ly-30-n*40);
}
for (n=1;n<=CPublic::nx;n++)
{
dc.MoveTo(30+n*50,CPublic::Ly-30);
dc.LineTo(30+n*50,50);
}
// x坐标标识
str.Format("时间(S)");
dc.TextOut(CPublic::Lx-60,CPublic::Ly-27,str);
// y坐标刻度及标识
for (n=0;n<=CPublic::ny;n++)
{
str.Format("%d",n*20);
dc.TextOut(3,CPublic::Ly-37-n*40,str);
}
str.Format("浓度(xxx)");
dc.TextOut(1,3,str);
// 绘制曲线
// 恢复以前画笔
dc.SelectObject(pOldPen);
delete pPenBlue;
delete pPenBlack;
}
void CPlotDemoDlg::DrawCurve(int AD,CTime T)
{
CPaintDC dc(this); // device context for painting
int n;
CString str;
// x和y的坐标值
int x,y;
CPen pen(PS_SOLID,0,RGB(255,0,8));
CPen* oldpen = NULL;
oldpen = dc.SelectObject(&pen);
// 存储实时数据
str_data data;
data.cent = AD;
data.time = T;
g_array.Add(data);
// 获取原点坐标
str_data Sd;
Sd = g_array[0];
int Sy;
Sy = CPublic::Ly-30-(Sd.cent)*2;
// 获取实时坐标,并设定开始时间
CTime St;
St = Sd.time;
CTimeSpan span = T-St;
int Hour = span.GetTotalHours();
int Min = span.GetTotalMinutes();
int Sec = span.GetTotalSeconds();
if (Sec>0 || Min>0 && Min<=10)
{
x = 30+Sec+Min*60;
CPublic::i++;
CPublic::j++;
CPublic::k++;
}
else if (Min>10 && Min<=60)
{
x = 30+Sec*1/6+Min*10;
CPublic::j++;
CPublic::k++;
}
else
{
x= 30+Sec*5/36+Min*5/6+Hour*50;
CPublic::k++;
}
y = CPublic::Ly-30-AD*2;
while(T==St)
{
str = T.Format("%h%m%s");
dc.TextOut(x-7,CPublic::Ly-27,str);
}
// 绘制实时曲线
if (Sec>0 || Min>0 && Min<=10)
{
dc.MoveTo(30,Sy);
dc.LineTo(x,y);
}
else if (Min>10 && Min<=60)
{
// 重绘前600s
while(CPublic::i==CPublic::j+1)
{
dc.MoveTo(30,Sy);
for (n=1;n<=CPublic::i;n++)
{
int tx,ty;
str_data td;
td = g_array[n];
CTimeSpan tspan = td.time-St;
int tMin = tspan.GetTotalMinutes();
int tSec = tspan.GetTotalSeconds();
tx = 30+Sec*1/6+Min*10;
ty = CPublic::Ly-30-(td.cent)*2;
dc.LineTo(tx,ty);
}
}
dc.LineTo(x,y);
}
else
{
// 重绘前60Min
while(CPublic::j==CPublic::k+1)
{
dc.MoveTo(30,Sy);
for (n=1;n<=CPublic::j;n++)
{
int tx,ty;
str_data td;
td = g_array[n];
CTimeSpan tspan = td.time-St;
int tHour = tspan.GetTotalHours();
int tMin = tspan.GetTotalMinutes();
int tSec = tspan.GetTotalSeconds();
tx = 30+Sec*5/36+Min*5/6+Hour*50;
ty = CPublic::Ly-30-(td.cent)*2;
dc.LineTo(tx,ty);
}
}
dc.LineTo(x,y);
}
dc.SelectObject(oldpen);
}