花了相当一段时间,把原来的曲线进行了升级,原有的曲线不是一个控件,是一个组合,坐标轴和图像控件的组合体,用起来多少是有点不方便,增加和减少曲线数量时,需要修改的地方比较多,没有动态增加,删除,修改的功能,原曲线只能支持秒级数据。此次将其封装为一个控件,支持到100纳秒,即以C#最小时间单位,支持X轴数据,Y轴数据格式的数据,也支持时间数据-Y轴数据格式。支持时间轴的自动更新。所有的坐标轴颜色,范围可在坐标轴上双击弹框修改,曲线的属性也可单击弹框后修改相关属性(如颜色,点框突出等),展示的界面如下:
在上图中,可修改的区域有很多,双击会根据区域的类型弹出不同的属性修改框,下图中描述:
双击1区为坐标轴的属性修改双击区,双击哪个坐标轴,弹出相应的弹框,如下:
双周颜色框可修改字体颜色,背景色以及坐标轴的背景色,设定坐标轴的上限,下限,坐标轴的分段数,显示的单位,格式(也许只有写程序的能看懂,后面再优化),宽度的属性放出来供调整,是为了防止有些数字范围很大的时候,文字显示不全,这时候可适当调整宽度。最小间隔,用于横坐标,不用于纵坐标。轴的停靠方式参数暂时没有放出来,只能在供码中定义,上图中之所以定义了一个右边的坐标轴,主轴是底部时间轴文字显示会占用右边不空间,即便是不定义右坐标轴,也会空白显示,有点浪费。
双击2区为时间轴,设置参数稍多了一点,目前支持的时候格式是:HH:mm:ss,即精确到秒,其他的自定义(此处后面也要优化,做几个选项直接选,不是写代码的拼不出这些字符)。这里面多了一个随当前时间变动,这个参数只是一个标识,主要是针对实时曲线的时间坐标轴不停的向左移动,勾选后,还是需要在代码里面找到时间轴的对象调用一个UpdateAxisTime()方法。宽度值无效。
双击3区,可修改每一个曲线的颜色及相关属性:
名称作为唯一可识别符,是不能修改的,因为曲线的所有修改属性是被保存的,下次调用的时候,会显示上一次的样子。文字描述宽度,是怕有时候文字太长了,显示不全,另外,由于曲线多了,3区的显示是一个动态调整的,即会自动换行,这样就不会因为控件的缩放而显示不完整,当然,控件缩到太小如400X300以下,不适合咱们这个控件显示哈。
双击4区,是大标题的属性,这个比较简单的,不列了。
双击5区,会动态滑出一个菜单,如下图:
该菜单10秒内没有操作,会自动滑入右侧,基本参数界面如下:
X轴自动缩放,Y轴自动缩放,设置到该模式时,相当于每次都会自动计算轴的最大,最小值,比较浪费时间,不建议用。
允许滚动缩放,即鼠标的滚轮上下滚动时,图像可放大缩小,,点框可见,是每个点外面画个框,数据量小可以用,量大就算了,费时间的。滚动的缩放大小,取决于缩放系数,太小了,缩放太慢,太大,则一下就没了。
曲线查看,三种模式:无操作,左键游标,该模式下,用左键点击图中曲线,会在鼠标点击的地方显示一个红色的竖线,同时会显示该处的所有可见曲线的X,Y值,如下图:
左键框选,该模式下,框选后,会放大曲线,将当前框放大到曲线可视范围。
背景色如果是软件是显示,建议是黑色,格栅用白色,如果是打印模式,则是白底,黑格。格栅数量,建议与坐标轴相一致,这样看着整齐。上个黑底白格的图吧:
当然颜色可随心调整,不仅仅是程序员,用户一样可随心随性。要的就是这种可修改的效果,但是啊,相当费神。这个曲线多多少少借鉴了QT中Chart控件,当然其源码有点复杂,我也只是取其中一瓢。
如何使用:
因为是控件,控件基于.net2.0,相对友好。引用控件后, 将控件拖到窗体中,拖进去的时候,有点丑陋,丑到爆啊,看图:
运行后就漂亮了。
在窗体中定义下面这些变量,从名字上好理解的。
//时间轴,放到窗体变量,是为了动态的操作
QAxis_Time XTimeAxial;
//曲线数据系列,放到窗体变量里,是为了操作,向里面添加数据
QSeries_Line Temp_B_Series;
QSeries_Line Temp_A_Series;
QSeries_Line Temp_E_Series;
QSeries_Line Tension_X_Series;
QSeries_Line Tension_Y_Series;
QSeries_Line Torque_Series;
QSeries_Line Power_Series;
QSeries_Line SetSpeed_Series;
QSeries_Line SpindleSpeed_Series;
QSeries_Line TorqueSpeed_Series;
//图表的数据模型
ChartDataSet ChartData;
接下来Form_Load事件里要写一些代码,
string SystemPath = Directory.GetCurrentDirectory().ToString() + "\\Parameter";
if (File.Exists(SystemPath) == false)
{
if (Directory.Exists(SystemPath) == false)
{
Directory.CreateDirectory(SystemPath);
}
}
ChartData = new ChartDataSet();
ChartData.ConfigFileName = SystemPath + "\\ChartSetting001.xml";
TitleSetting mTitle = new TitleSetting();
mTitle.TitleName = "实时曲线图";
mTitle.LabelFont = new Font("宋体", 20, FontStyle.Bold);
mTitle.ForeColor = Color.Black;
ChartData.Title = mTitle;
//X轴时间轴******************************************************************************
XTimeAxial = new QAxis_Time();//必须的
XTimeAxial.AxisName = "时间";//必须的
XTimeAxial.Visible = true;
Int64 QDateTime = DateTime.Now.Ticks;
TimeSpan TSpan = new TimeSpan(0, 5, 0);
Int64 EndTime = DateTime.Now.Add(TSpan).Ticks;
XTimeAxial.setRange(QDateTime, EndTime);
XTimeAxial.alignment = Alignment.AlignBottom;//底部,那就是横坐标
XTimeAxial.FormatOutput = "HH:mm:ss";
ChartData.AddAxis(XTimeAxial);
//纵坐标(温度)
QAxis_XY YAxial_Temp = new QAxis_XY();//必须的
YAxial_Temp.AxisName = "温度";//必须的
YAxial_Temp.LabelsForeColor = Color.Blue;
YAxial_Temp.Unit = "℃";
YAxial_Temp.setRange(0, 100);
YAxial_Temp.alignment = Alignment.AlignLeft;//左边,那就是纵坐标
ChartData.AddAxis(YAxial_Temp);
//纵坐标2(扭矩)
QAxis_XY YAxial_Torque = new QAxis_XY();//必须的
YAxial_Torque.AxisName = "扭矩";//必须的
YAxial_Torque.LabelsForeColor = Color.BlueViolet;
YAxial_Torque.Unit = "NM";
YAxial_Torque.setRange(0, 100);
YAxial_Torque.alignment = Alignment.AlignLeft;
ChartData.AddAxis(YAxial_Torque);
//纵坐标3(力)
QAxis_XY YAxial_Tension = new QAxis_XY();//必须的
YAxial_Tension.AxisName = "推力";//必须的
YAxial_Tension.LabelsForeColor = Color.Green;
YAxial_Tension.Unit = "N";
YAxial_Tension.setRange(0, 5000);
YAxial_Tension.alignment = Alignment.AlignLeft;
ChartData.AddAxis(YAxial_Tension);
//转速
QAxis_XY YAxial_Speed = new QAxis_XY();//必须的
YAxial_Speed.AxisName = "转速";//必须的
YAxial_Speed.LabelsForeColor = Color.OrangeRed;
YAxial_Speed.Unit = "rpm";
YAxial_Speed.setRange(0, 10000);
YAxial_Speed.alignment = Alignment.AlignLeft;
ChartData.AddAxis(YAxial_Speed);
//输出功率
QAxis_XY YAxial_Power = new QAxis_XY();//必须的
YAxial_Power.AxisName = "输出功率";//必须的
YAxial_Power.LabelsForeColor = Color.Cyan;
YAxial_Power.Unit = "KW";
YAxial_Power.setRange(0, 20);
YAxial_Power.alignment = Alignment.AlignRight;
ChartData.AddAxis(YAxial_Power);
Temp_B_Series = new QSeries_Line();//必须的
Temp_B_Series.Name = "前轴承T";//必须的
Temp_B_Series.Text = "前轴承T";
Temp_B_Series.LineColor = Color.Blue;
Temp_B_Series.PointPen = new Pen(Color.Lime);
Temp_B_Series.AttachAxis(XTimeAxial, YAxial_Temp);//关联坐标轴
Temp_A_Series = new QSeries_Line();//必须的
Temp_A_Series.Name = "后轴承T";//必须的
Temp_A_Series.Text = "后轴承T";
Temp_A_Series.LineColor = Color.DeepSkyBlue;
Temp_A_Series.PointPen = new Pen(Color.DeepSkyBlue);
Temp_A_Series.AttachAxis(XTimeAxial, YAxial_Temp);//关联坐标轴
Temp_E_Series = new QSeries_Line();//必须的
Temp_E_Series.Name = "环境T";//必须的
Temp_E_Series.Text = "环境T";
Temp_E_Series.LineColor = Color.DarkBlue;
Temp_E_Series.PointPen = new Pen(Color.DarkBlue);
Temp_E_Series.AttachAxis(XTimeAxial, YAxial_Temp);//关联坐标轴
Tension_X_Series = new QSeries_Line();//必须的
Tension_X_Series.Name = "轴向力";//必须的
Tension_X_Series.Text = "轴向力";
Tension_X_Series.LineColor = Color.Lime;
Tension_X_Series.PointPen = new Pen(Color.Lime);
Tension_X_Series.AttachAxis(XTimeAxial, YAxial_Tension);//关联坐标轴
Tension_Y_Series = new QSeries_Line();//必须的
Tension_Y_Series.Name = "径向力";//必须的
Tension_Y_Series.Text = "径向力";
Tension_Y_Series.LineColor = Color.Green;
Tension_Y_Series.PointPen = new Pen(Color.Green);
Tension_Y_Series.AttachAxis(XTimeAxial, YAxial_Tension);//关联坐标轴
Torque_Series = new QSeries_Line();//必须的
Torque_Series.Name = "扭矩";//必须的
Torque_Series.Text = "扭矩";
Torque_Series.LineColor = Color.BlueViolet;
Torque_Series.PointPen = new Pen(Color.BlueViolet);
Torque_Series.AttachAxis(XTimeAxial, YAxial_Torque);//关联坐标轴
SetSpeed_Series = new QSeries_Line();//必须的
SetSpeed_Series.Name = "设定速度";//必须的
SetSpeed_Series.Text = "设定速度";
SetSpeed_Series.LineColor = Color.OrangeRed;
SetSpeed_Series.PointPen = new Pen(Color.OrangeRed);
SetSpeed_Series.AttachAxis(XTimeAxial, YAxial_Speed);//关联坐标轴
SpindleSpeed_Series = new QSeries_Line();//必须的
SpindleSpeed_Series.Name = "编码器转速";//必须的
SpindleSpeed_Series.Text = "编码器转速";
SpindleSpeed_Series.LineColor = Color.DarkOrange;
SpindleSpeed_Series.PointPen = new Pen(Color.DarkOrange);
SpindleSpeed_Series.AttachAxis(XTimeAxial, YAxial_Speed);//关联坐标轴
TorqueSpeed_Series = new QSeries_Line();//必须的
TorqueSpeed_Series.Name = "扭矩速度";//必须的
TorqueSpeed_Series.Text = "扭矩速度";
TorqueSpeed_Series.LineColor = Color.Salmon;
TorqueSpeed_Series.PointPen = new Pen(Color.Salmon);
TorqueSpeed_Series.AttachAxis(XTimeAxial, YAxial_Speed);//关联坐标轴
Power_Series = new QSeries_Line();//必须的
Power_Series.Name = "功率";//必须的
Power_Series.Text = "功率";
Power_Series.LineColor = Color.Cyan;
Power_Series.PointPen = new Pen(Color.Cyan);
Power_Series.AttachAxis(XTimeAxial, YAxial_Power);//关联坐标轴
ChartData.AddSeries(Temp_B_Series);
ChartData.AddSeries(Temp_A_Series);
ChartData.AddSeries(Temp_E_Series);
ChartData.AddSeries(Tension_X_Series);
ChartData.AddSeries(Tension_Y_Series);
ChartData.AddSeries(Torque_Series);
ChartData.AddSeries(SetSpeed_Series);
ChartData.AddSeries(SpindleSpeed_Series);
ChartData.AddSeries(TorqueSpeed_Series);
ChartData.AddSeries(Power_Series);
//显示到图
chartView1.ChartData = ChartData;
chartView1.Left = 0;
chartView1.Top = BT_Print.Height;
chartView1.Width = this.Width - 20;
chartView1.Height = this.Height - 60 - BT_Print.Height;
chartView1.StartAutoFresh();//启动自动刷新,即控件内定时器,以设定的时候,进行自动刷新曲线。
如果是外部代码操作,可以调用:
chartView1.ShowChart();
窗体调整的时候,把控件大小进行自动调整,其他控件自行调整:
private void Form1_Resize(object sender, EventArgs e)
{
chartView1.Left = 0;
chartView1.Top = BT_Print.Height ;
chartView1.Width = this.Width-20;
chartView1.Height = this.Height - 60 - BT_Print.Height;
chartView1.ShowChart();
}
定时器里添加数据:
private void timer1_Tick(object sender, EventArgs e)
{
Random rd = new Random(); //无参即为使用系统时钟为种子
index++;
float y = 2.5f+2.0f* rd.Next(0,5) ;
Temp_B_Series.append(DateTime.Now.Ticks, y);//向其中一组曲线添加数据
if (XTimeAxial.TimeFollow == true)
{
XTimeAxial.UpdateAxisTime();//刷新时间轴,主要针对实时曲线用
}
//chartView1.ShowChart();
}
快要告一段落了,接下来,做数据采集的时候,方便许多,完成一个灵活,自由的曲线控件着实不易。不是不会,而是时间挤不出,所以如果有幸有需要,可联系我微信wizzly,可给试用版,估计是加个水印,正式用的时候,需要收费的,估个价5000元/套(估计用的人不会多,多了可以便宜)。