C# 历史曲线控件 基于时间的曲线控件 可交互的高级曲线控件 HslControls曲线控件使用教程
本篇博客主要对 HslControls 中的曲线控件做一个详细的教程说明,大家可以根据下面的教程开发出高质量的曲线控件
联系作者及加群方式(激活码在群里发放):http://www.hslcommunication.cn/Cooperation
Prepare
先从nuget下载到组件,然后就可以使用组件里的各种组件信息了。
在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装:
Install-Package HslControls
NuGet安装教程 http://www.cnblogs.com/dathlin/p/7705014.html
Demo
demo项目的源代码,https://github.com/dathlin/HslControlsDemo
有一个demo程序可以下载,地址为 demo.zip
所支持的控件信息如下:
曲线控件先上图,看看
适用场景
正式开始文章之前,我们先来看看这个曲线控件到底为了解决什么样子的问题的,在工业的场景中,我们会采集一些设备的工艺参数信息,比如锅炉和模具温度,锅炉压力,仓库湿度,等等情况的信息,我们会在数据库建立一张数据表,可能2秒钟存储一条数据,可能5秒钟存储一条数据等等,甚至可能30秒,现在我们有数据了,需要将数据进行显示出来,使用本控件即可以快速的开发可交互式的曲线显示。
如下就是一个数据库的示例
曲线显示
当然实际中你可以根据自己的情况来,不过这都无所谓,应该本控件是需要传入处理过的数据的,ok,我们现在界面上拖一个控件
先调整两侧坐标轴的,比如温度的范围是0-250,压力的范围是0-5,我们就调整这个控件的属性来实现功能
还可以调整分割线的情况,我们调整成如下的数据
然后显示如下:
我们再调整下文字,设置为空,在新增一个按钮,点击的时候就要去数据库查询数据了,由于查询的时间不定,需要花费一些时间,我们还需要进行友好的提示信息,比如正在查询数据...
然后我们完善代码
private void button1_Click( object sender, EventArgs e )
{
hslCurveHistory1.Text = "正在加载数据...";
hslCurveHistory1.RemoveAllCurve( );
new Thread( new ThreadStart( ThreadReadExample1 ) ) { IsBackground = true }.Start( );
} private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.RenderCurveUI( );
} ) );
} private Random random = new Random( );
此处只有一条曲线,横轴还没设置,这已经是最简单的曲线显示了,而且支持按钮多次重复点击,不会发生数据叠加。效果如下:
当光标移动的时候,还会提示当前的光标所在位置的数据信息,目前所具备的功能还是比较简单的,我们从数据库获取到数据,通常还包含了时间轴,此处就要传入同等数量长度的时间轴信息
注意,时间轴是随着时间逐渐增加的信息,确保是单向增加的。
所以我们的代码改成如下:
private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
DateTime[] times = new DateTime[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
times[i] = DateTime.Now.AddSeconds( i - 2000 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.RenderCurveUI( );// 所有的曲线设置好后,调用这个方法统一显示曲线信息,这样的设计可以有效的避免闪烁的问题
} ) );
}
这时候的效果已经改变了。最下面已经多了一个时间的信息显示。
这时候我们在图形的任意区域点击鼠标左键,然后移动鼠标,然后再松开鼠标左键就会发生填充辅助曲线信息
这时候可以多次的重复操作,可以标记多个图形信息。
如果想要清除上面的所有的数据信息,怎么办?右键点击下图形的任意界面,所有的辅助曲线就不存在了。
接下来我们再增加一条曲线,压力相关的,再看看效果。
private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
float[] press = new float[2000];
DateTime[] times = new DateTime[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
times[i] = DateTime.Now.AddSeconds( i - 2000 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.RenderCurveUI( );
} ) );
}
效果如下:
假设我还有个步序的信息,只想在曲线里提示出来,但是不想显示步序曲线,应该怎么操作呢
private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
float[] press = new float[2000];
float[] steps = new float[2000];
DateTime[] times = new DateTime[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
times[i] = DateTime.Now.AddSeconds( i - 2000 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.SetLeftCurve( "步序", steps );
hslCurveHistory1.SetCurveVisible( "步序", false ); // 不显示曲线信息
hslCurveHistory1.RenderCurveUI( );
} ) );
}
这样之后我们就可以显示步序的提示信息,但是不显示步序的曲线。
这里有个小问题,如果我希望步序显示顺序在最上面怎么办?或者是这里的提示信息是根据什么顺序来排序的?
答案是曲线的添加顺序,我们只需要调整曲线添加的顺序即可。如下:
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "步序", steps );
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.SetCurveVisible( "步序", false ); // 不显示曲线信息
hslCurveHistory1.RenderCurveUI( );
到这里为止,曲线控件的简单应用已经差不多了,已经实现了一般的情况的应用了。接下来就是比较高级的操作了。
高级操作
在高级的操作之前,需要先普及个概念,贯穿于这个曲线控件的所有的部分。这个概念就是数据点位的信息,比如我们有2000个数据,那么数据点位就是0-1999,在图形上显示不一定是0-1999的位置,存在一个缩放的等级,默认缩放等级是1,也就是说0-1999就是0-1999,如果我们的缩放等级调整为2,那么就是放大,0-1999对应 0-3998,如果缩放等级为0.5,那么就是缩小一倍,0-1999对应0-999
单位显示
显示单位的信息
这样就可以在图形里显示
隐藏右坐标
如果我们想要隐藏右坐标轴信息,可以设置下面的属性
将这个值设置为 False 后,就不显示右坐标了,如下:
辅助线功能
如果我们需要标记一段特殊的虚线,可以是报警的分界线,也可以是重点的线。操作如下:在窗体的载入中添加如下的代码即可
private void FormCurveDemo_Load( object sender, EventArgs e )
{
hslCurveHistory1.AddLeftAuxiliary( 172f );
}
效果如下:
当然我们也可以指定颜色
private void FormCurveDemo_Load( object sender, EventArgs e )
{
hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
}
当然也可以添加右曲线信息
缩放功能
如果你觉得目前的数据点位太多了,曲线太长了,可以进行缩小,那么可以设置缩放等级,在窗口载入的时候设置一次即可。
private void FormCurveDemo_Load( object sender, EventArgs e )
{
hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
hslCurveHistory1.SetScaleByXAxis( 0.5f );
}
接下来我们看看缩放等级设置为4的效果
private void FormCurveDemo_Load( object sender, EventArgs e )
{
hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
hslCurveHistory1.SetScaleByXAxis( 4f );
}
数据点标注操作
我们现在有个需求,我们有了曲线以后,可能对其中的某个或是多个特殊的点进行文本标注,本控件支持这样的操作,以及标注不同的颜色的信息
hslCurveHistory1.AddMarkText( new HslControls.HslMarkText( )
{
Index = 200,
CurveKey = "温度",
MarkText = "标注信息",
CircleBrush = Brushes.DodgerBlue,
TextBrush = Brushes.Blue
} );
hslCurveHistory1.RenderCurveUI( );
当然也可以指定文本的方向,如果想要清除,那么调用
hslCurveHistory1.RemoveAllMarkText( );
hslCurveHistory1.RenderCurveUI( );
数据线标注操作
我们现在又有个需求,需要对曲线里的一个区域画线标注出来。并且可以再标注点信息
// 增加一个三角形的线段标记示例 Points的每个点的X是数据索引,Y是数据值(需要选对参考坐标轴,默认为左坐标轴)
hslCurveHistory1.AddMarkLine( new HslControls.HslMarkLine( )
{
CircleBrush = Brushes.DodgerBlue,
IsLeftFrame = true,
IsLineClosed = true,
LinePen = Pens.DodgerBlue,
TextBrush = Brushes.DodgerBlue,
Points = new PointF[]
{
new PointF(200, 180f), new PointF(260, 20f), new PointF(550, 150f),
},
Marks = new string[] { "AA", "BB", "CC" },
} );
效果如下:
背景标识操作
我们现在有个需求,我们有了步序之后就可以分析出曲线对应的产品信息,比如分析出点位是从1000点开始到1300点结束的,是一个产品,条码是 K1234567890 ,现在要在曲线里显示出来。我们来看看如果通过代码实现
我们先调整为正常的缩放等级,也就是1f,
private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
float[] press = new float[2000];
float[] steps = new float[2000];
DateTime[] times = new DateTime[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
times[i] = DateTime.Now.AddSeconds( i - 2000 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "步序", steps );
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.SetCurveVisible( "步序", false ); // 不显示曲线信息 HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
{
StartIndex = 1000,
EndIndex = 1300,
MarkText = "K1234567890",
};
hslCurveHistory1.AddMarkBackSection( backSection ); hslCurveHistory1.RenderCurveUI( );
} ) );
} private Random random = new Random( ); private void FormCurveDemo_Load( object sender, EventArgs e )
{
hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
}
代码上来说,就是新增一个 backSection 对象,至于1000和1300怎么分析出来的,就是要自己写代码实现了,简单的说,通过遍历数据,前后对比可以实现。运行效果如下:
可以清楚的看到有一个颜色稍微淡一点点的标记层,如果你的缩放等级是0.5,那么这个阴影的宽度会减少一半,这都是自动适应的。
当然你也可以添加多个背景的标记,如果想要清除标记,只能调用清除所有曲线的方法,
如下是缩放等级为0.5的情况
区间标识操作
我们现在有另外的需求,需要标记某些特殊的区间,比如某个区间发生了报警,例如区间 600-700发生了报警,内容为“温度超标了”;应该怎么操作
private void ThreadReadExample1( )
{
// 模拟下查询时间
Thread.Sleep( 2000 ); // 这里数据数据,实际应该是你的真实的数据
float[] temp = new float[2000];
float[] press = new float[2000];
float[] steps = new float[2000];
DateTime[] times = new DateTime[2000];
for (int i = 0; i < temp.Length; i++)
{
temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
times[i] = DateTime.Now.AddSeconds( i - 2000 );
} // 显示出数据信息来
Invoke( new Action( ( ) =>
{
// 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
hslCurveHistory1.SetLeftCurve( "步序", steps );
hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
hslCurveHistory1.SetDateTimes( times );
hslCurveHistory1.SetCurveVisible( "步序", false ); // 不显示曲线信息 HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
{
StartIndex = 1000,
EndIndex = 1300,
MarkText = "K1234567890",
};
hslCurveHistory1.AddMarkBackSection( backSection ); HslControls.HslMarkForeSection foreSection = new HslControls.HslMarkForeSection( )
{
StartIndex = 600,
EndIndex = 800,
StartHeight = 0.3f, // 如果值是(0-1)的话,表示的是位置百分比,0.9就是曲线高度为90%,从上往下看的视角,如果填了600,那就是绝对坐标
Height = 0.9f, // 和上面同理
LinePen = Pens.Chocolate, // 指定颜色
IsRenderTimeText = false, // 是否显示额外的起始时间和结束时间,此处就不要了
MarkText = "温度超标了",
};
hslCurveHistory1.AddMarkForeSection( foreSection ); hslCurveHistory1.RenderCurveUI( ); // 将曲线显示出来
} ) );
}
如上图,我们完成了标记信息的添加,上述 的几个属性,你可以修改试试看,然后运行看看效果。上述的效果如下:
当然了,文字的颜色也可以设定的,用于不同功能的区段的提醒,这个区段也是支持自动的缩放的。
双击曲线操作
如果你想捕获鼠标双击曲线的事件,获取到数据的索引或是实际的时间信息,好进行一些额外的操作,比如打印双击时间附近的曲线,生成报告单之类的情况,就显得很有用了。那么应该怎么做呢?
在这个事件里双击生成事件即可。
private void hslCurveHistory1_onCurveDoubleClick( HslControls.HslCurveHistory hslCurve, int index, DateTime dateTime )
{
MessageBox.Show( $"Index: {index} Time:{dateTime.ToString( )}" );
}
自然会生成上述的代码,其中index就是数据索引,和图形的缩放是自动适应的,还有时间信息,也是可以一并获取到的,可以进行额外的处理。
两个曲线控件同步操作
如果你有个需求。有两个曲线控件,时间轴是一模一样的,想要鼠标挪动的时候,让另一个曲线也跟着动,或是互相一起动,再或是是光标也实现一起运动,这东西解释起来比较复杂,先上效果图:
首先我先放两个控件,曲线1和曲线2,如果想让曲线2跟随曲线1移动
hslCurveHistory1.Scroll += (sender1 , e1) => hslCurveHistory2.SetScrollPosition( e1 );
如果想要实现互相跟随
hslCurveHistory1.Scroll += (sender1 , e1) => hslCurveHistory2.SetScrollPosition( e1 );
hslCurveHistory2.Scroll += ( sender1, e1 ) => hslCurveHistory1.SetScrollPosition( e1 );
光标移动也是同理,互相移动参考如下:
hslCurveHistory1.onCurveMouseMove += ( curve, x, y ) => hslCurveHistory2.SetCurveMousePosition( x, y );
hslCurveHistory2.onCurveMouseMove += ( curve, x, y ) => hslCurveHistory1.SetCurveMousePosition( x, y );
主题调整操作
当然,你不喜欢暗色主题的话,通过调整所有的颜色配置,来达到亮色的主题的话,如下的配置只是一个示例
配色的结果如下:
好了,更详细的就参考demo项目的源代码,https://github.com/dathlin/HslControlsDemo
C# 历史曲线控件 基于时间的曲线控件 可交互的高级曲线控件 HslControls曲线控件使用教程的更多相关文章
- 基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重 ...
- 关于jquery日期控件及时间格式转换2017.05.27
开始时间:<input type="date" id="starttime" class="time"/>//data为日期控件 ...
- 基于CkEditor实现.net在线开发之路(3)常用From表单控件介绍与说明
上一章已经简单介绍了CKEditor控件可以编写C#代码,然后可以通过ajax去调用,但是要在网页上面编写所有C#后台逻辑,肯定痛苦死了,不说实现复杂的逻辑,就算实现一个简单增删改查,都会让人头痛欲裂 ...
- MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件
类似于多层级的角色与权限控制功能,用MVC实现MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件.最近我们的项目中需要用到树型菜单,以前使用WebForm时,树型菜单有微软提供的 ...
- mysql基于“时间”的盲注
无需页面报错,根据页面响应时间做判断! mysql基于时间的盲注 =================================================================== ...
- 表空间基于时间点的恢复(TSPITR)
环境:RHEL 6.4 + Oracle 11.2.0.4 准备模拟环境 1. 验证表空间的依赖性 2. 确定执行TSPITR后会丢失的对象 3. 自动执行TSPITR Reference 准备模拟环 ...
- JavaScript基于时间的动画算法
转自:https://segmentfault.com/a/1190000002416071 前言 前段时间无聊或有聊地做了几个移动端的HTML5游戏.放在不同的移动端平台上进行测试后有了诡异的发现, ...
- 如何让窗口控件半透明(控件在Paint自己时,首先向主窗口询问,获取主窗口上控件所在区域的背景图)
在网上关于窗口视觉效果,有2个问题被问得最多:第一个是如何让窗口边框有阴影效果?第二个是如何让窗口控件有半透明效果? 对于第一个问题,我们的答案是用双层窗口模拟或是用Layered Window.在X ...
- 7.5.1 Point-in-Time Recovery Using Event Times 使用Event Times 基于时间点恢复
7.5.1 Point-in-Time Recovery Using Event Times 使用Event Times 基于时间点恢复 表明开始和结束时间用于恢复, 指定 --start-datet ...
随机推荐
- ASP.NET MVC 中使用Ckeditor4.5 编辑器
一.在项目中添加Ckeditor4.5.11 (1) 新建 ASP.NET MVC5项目,解压缩ckeditor_4.5.11_standard.zip,在VS2015的解决方案资源管理器中将得到的“ ...
- MVC ---- Manager.ttinclude内容
http://www.infoq.com/cn/news/2009/11/T4-Multiple-Output 初次认识并尝试使用T4生成代码的时候,相关学习资料似乎比较少.不过现在VS2010 的M ...
- Java中的this
首先this作为关键字其实是随着对象的创建而产生的,当我们调用对象的一个方法的时候: 例如: A a = new A(); a.f(1) 其实我们可以理解为a.f(a,1) 编译器默默的把所操作的对 ...
- vim/vi中移动光标键会变成A,B,C,D的解决办法
在某些情况下, vi/vim中的编辑会出现一些很不愉快的情况, 比如在vi/vim中输入方向键有时被转化为A B C D, 或者按个Enter键, 却被转为为其他字母, 恼人得很, 该怎么办呢? 方法 ...
- Windows系统下在Eclipse中集成Python
我现在偶尔开发代码,已经不用Eclipse了,主要原因是查看Jar包中的代码反编译十分不便,项目加载的时候卡,偶尔还会崩溃 用Intellij IDEA和PyCharm 原来的笔记如何在Eclipse ...
- PHP 高精度比较bccomp
/** * 比较大小 */ public static function compareNum($num1,$num2) { return bccomp($num1,$num2,3); // 精确到小 ...
- Qt5.3.2_Oracle驱动
参考网址:http://blog.csdn.net/sdqyhn/article/details/39855847 ZC: 将编译好的 qsqloci.dll和qsqlocid.dll 放到 目录“E ...
- Flutter学习笔记(五)
一.Container 是一个便利的Widget,它把通用的绘制.定位和Widget的大小结合了起来. Container会先用padding填充子Widget和border之间的空白,然后添加其他的 ...
- tp3.x和tp 5的区别
由于TP5.0是一个全新的颠覆重构版本,所以现在面试很多面试官喜欢问TP3.2和TP5之间的区别,那他们之间到底有哪些区别呢?一.目录 TP5目录 二.需要摒弃的 3.X 旧思想 模型的变动 ...
- Confluence 6 设置公共访问备注
你不能为匿名用户赋予空间管理员或者限制权限. 你可以让用户自行注册你的 Confluence 站点,同时也可以选择其他的用户注册选项,比如邀请用户注册等.请查看:Add and Invite User ...