C# Winform GDI大量数据(几万个数据)绘图刷新问题

Steve_Amoy 2016-05-14 10:56:26
做一个项目,使用C# GDI画图,以达到可视化目的,使用自定义的控件,整个控件通过CreateGraphics()来绘图,数据存放在DataTable有几万行的数据,需要用多列(有十几列,根据不同需要来决定使用不同的列绘图)来绘图,使用GDI如下:
      
public void PaintGraph(Rectangle drawRectangle)
{
lock (refresh_lock)
{
BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
BufferedGraphics myBuffer = currentContext.Allocate(this.CreateGraphics(), drawRectangle);
Graphics g = myBuffer.Graphics;
//绘制边框和座标轴图像
DrawBackGround(g);
//画线条
DrawSeries(g);
//画十字线
if (showCrossHair)
{
DrawCrossHair(g);
}
myBuffer.Render();
myBuffer.Dispose();
}
}


在DrawSeries(g)时如下(Data是PointF(,)类型),由于会经常会使用方向向上进行放大,向下进行缩小;使用方向键向左或向右快速查看上一行或下一行的数据的一些信息(绘制在旁边)。
每次放大或缩小时,座标轴需要根据当前的数据识别最大值和最小值,然后将每个数据重新计算出新的座标,再画图;
每次向左或向右时,若有出现新的数据,也需要根据当前的数据识别最大值和最小值,然后将每个数据重新计算出新的座标,再画图;
 
for (int lsJ = 0; lsJ < LineSeriesList.Count; lsJ++)
{
LineSeries ls = LineSeriesList[lsJ];
for (int i = 0; i < ls.Data.Count() - 1; i++)
{
g.DrawLine(ls.LinePen, ls.Data[i], ls.Data[i + 1]);
}
}


问题是,使用方向键连续地放大、缩小,或者连续地向左或向右的时候,刷新会很卡,有时方向键停下来,控件还会延时3-5秒左右才显示完,有什么方法可以提示效率吗?
...全文
1876 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Steve_Amoy 2016-06-07
  • 打赏
  • 举报
回复
引用 13 楼 wk_knife 的回复:
1.自己的usercontrol在构造函数里加上双缓冲-true; 2.drawline当然慢了,要drawLines,类似polyline,首先就会快几倍。 3.所有的绘制代码都应该放在onpaint里,其他事件里只是调用invalidate; 4.裁剪clip:只绘制无效区内部的部分。滚动的时候每次都是增加一点点无效区而已。 采用1、2、3点后,你的绘图效果应该就可以接受了。 采用4点后就基本不会有任何问题了。 多线程、拟合之类的绘几十万上百万点的时候再考虑就行了。这么点数据真不需要多线程(当然有也更好)。
谢谢。
EP外星人 2016-05-31
  • 打赏
  • 举报
回复
1.自己的usercontrol在构造函数里加上双缓冲-true; 2.drawline当然慢了,要drawLines,类似polyline,首先就会快几倍。 3.所有的绘制代码都应该放在onpaint里,其他事件里只是调用invalidate; 4.裁剪clip:只绘制无效区内部的部分。滚动的时候每次都是增加一点点无效区而已。 采用1、2、3点后,你的绘图效果应该就可以接受了。 采用4点后就基本不会有任何问题了。 多线程、拟合之类的绘几十万上百万点的时候再考虑就行了。这么点数据真不需要多线程(当然有也更好)。
Steve_Amoy 2016-05-31
  • 打赏
  • 举报
回复
引用 11 楼 wzn721721 的回复:
使用独立的线程去绘制 每次要绘制时判断绘制线程是否执行完毕 若未完毕 直接终止线程重新绘制
可以试下,谢谢。
mnxm 2016-05-28
  • 打赏
  • 举报
回复
使用独立的线程去绘制 每次要绘制时判断绘制线程是否执行完毕 若未完毕 直接终止线程重新绘制
Steve_Amoy 2016-05-27
  • 打赏
  • 举报
回复
引用 9 楼 wzn721721 的回复:
假设点击一次放大或缩小需要耗费1s进行绘制 如果你连续点击4次,可能需要4s进行绘制 但此时前3次绘制是没有意义的,只需要1s做最后一次的绘制 这个细节你考虑了没? (从你所说的“方向键连续地放大、缩小,或者连续地向左或向右的时候,刷新会很卡”,推测可能没有考虑)
怎么去判断和提前中断呢?
mnxm 2016-05-25
  • 打赏
  • 举报
回复
假设点击一次放大或缩小需要耗费1s进行绘制 如果你连续点击4次,可能需要4s进行绘制 但此时前3次绘制是没有意义的,只需要1s做最后一次的绘制 这个细节你考虑了没? (从你所说的“方向键连续地放大、缩小,或者连续地向左或向右的时候,刷新会很卡”,推测可能没有考虑)
Steve_Amoy 2016-05-25
  • 打赏
  • 举报
回复
谁还有什么好的建议吗?
assky124 2016-05-16
  • 打赏
  • 举报
回复
1.绘图用控件的OnPaint或者Paint 事件,不要自己创建 画布,频繁的创建,影响效率 2.考虑使用图片,预生成,或者缓存部分绘图 3.抽样或者曲线拟合,对数据进行预处理 或者干脆用控件算了,比如TeeChart
Steve_Amoy 2016-05-16
  • 打赏
  • 举报
回复
引用 6 楼 assky124 的回复:
1.绘图用控件的OnPaint或者Paint 事件,不要自己创建 画布,频繁的创建,影响效率 2.考虑使用图片,预生成,或者缓存部分绘图 3.抽样或者曲线拟合,对数据进行预处理 或者干脆用控件算了,比如TeeChart
显示内容只能自定义,因为会有太多细节需要自己来定义。 现在的问题是放大和缩小时,区间不固定,没办法使用预生成。
Steve_Amoy 2016-05-15
  • 打赏
  • 举报
回复
引用 2 楼 xuzuning 的回复:
你不可能把几万个数据都都画在屏幕上,即使画上了,字迹也会小的看不清(没有实用价值) 所以你实际只去了一小部分数据进行展示,因此说原始数据有多么多么多是没有意义的 我不知道你那些自定义方法内部是怎么做的 仅就方向键控制放大缩小而言,应该是将图元绘制在 GraphicsPath 中,通过仿射矩阵(Matrix)完成的
使用GraphicsPath,在放大和缩小时,因要重新计算所有的GraphicsPath,效率变差了; 在向左和向右移,只要不需重新计算GraphicsPath,效率确实提高很多,在一般的移动十字线不会有延时感。 Matrix的问题正在学习,因是放大或缩小,所有的像素位置都要重新计算,而且数据区间会不一样,感觉Matrix不一定能用得上,今天先试试。 谢谢。
足球中国 2016-05-15
  • 打赏
  • 举报
回复
现在的计算机的性能远没有这么高。满屏幕1440*960 想全部填充文字都反应不过的。但还有一群程序员,写的代码随意的浪费服务器资源。 你这个只有想折中的方法了,不全部显示。或者平滑过度之类的。
xuzuning 2016-05-14
  • 打赏
  • 举报
回复
你不可能把几万个数据都都画在屏幕上,即使画上了,字迹也会小的看不清(没有实用价值) 所以你实际只去了一小部分数据进行展示,因此说原始数据有多么多么多是没有意义的 我不知道你那些自定义方法内部是怎么做的 仅就方向键控制放大缩小而言,应该是将图元绘制在 GraphicsPath 中,通过仿射矩阵(Matrix)完成的
john_QQ:2335298917 2016-05-14
  • 打赏
  • 举报
回复
进行抽样,或者找出画图的数据范围,只画一部分。如果数据是连续的,在抽样的时候还可以取个均值
Steve_Amoy 2016-05-14
  • 打赏
  • 举报
回复
引用 1 楼 johnliuyuan 的回复:
进行抽样,或者找出画图的数据范围,只画一部分。如果数据是连续的,在抽样的时候还可以取个均值
因是数据分析,希望看到实际的数据变化情况,进行抽样是个不错的方向,也有试用,基本上把3万条数据抽样成4000左右(图形看起来不会失真太严重),如果条线少还好,有时同一个界面,可能会存在10几条折线(对比不同系列,及不同指标),还是没办法解决这个问题。

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧