LZ最近有一个项目方案无从下手,希望大家帮帮忙
具体是这样的:要在显示界面上实现一个图形的连续移动,背景是本人绘制并且不定期局部刷新,显示的图形为自定义的折线段和文字。接收位置信息之后,进行图形的实时绘制,要求每秒处理100~1000条数据。
原本的方案是这样的:使用双层画布,一个绘制背景,一个绘制图形(图形的背景设为透明),当背景或图形位置变化时,将需要刷新区域的背景和图形调用DrawImage()函数,叠加到显示界面。
这样是可以实现连续移动的,但是无法达到每秒处理100~1000条数据的要求;原因是DrawImage函数需要时间,导致CPU占用率也很高。
请高手们帮帮忙。
具体是这样的:要在显示界面上实现一个图形的连续移动,背景是本人绘制并且不定期局部刷新,显示的图形为自定义的折线段和文字。接收位置信息之后,进行图形的实时绘制,要求每秒处理100~1000条数据。
原本的方案是这样的:使用双层画布,一个绘制背景,一个绘制图形(图形的背景设为透明),当背景或图形位置变化时,将需要刷新区域的背景和图形调用DrawImage()函数,叠加到显示界面。
这样是可以实现连续移动的,但是无法达到每秒处理100~1000条数据的要求;原因是DrawImage函数需要时间,导致CPU占用率也很高。
请高手们帮帮忙。
解决方案
25
就是嘛,你的做法是有问题的
1、其实你的背景并没有变,只是原因是擦除的部分区域,所以才需要补上
2、实时数据产生的图形不是实时绘制的,而是绘制在备份上复制过来的
这就是说,你完成一次更新,需要 擦除,复制背景,画备份,复制备份 这四个步骤
其实 作为背景的图片放在 PictureBox.Image 中是不会被清除掉的,哪怕被其他窗口覆盖过了
绘图应在 Paint 事件中完成。当 Paint 事件到来时 PictureBox 的全部绘图都会被自动消除(除了 Image)
你只需重新绘制就可以了。新旧数据按次序保存在一个序列里,绘制时只取需要的一段(只要每次的起点不同,自然就动起来了)
1、其实你的背景并没有变,只是原因是擦除的部分区域,所以才需要补上
2、实时数据产生的图形不是实时绘制的,而是绘制在备份上复制过来的
这就是说,你完成一次更新,需要 擦除,复制背景,画备份,复制备份 这四个步骤
其实 作为背景的图片放在 PictureBox.Image 中是不会被清除掉的,哪怕被其他窗口覆盖过了
绘图应在 Paint 事件中完成。当 Paint 事件到来时 PictureBox 的全部绘图都会被自动消除(除了 Image)
你只需重新绘制就可以了。新旧数据按次序保存在一个序列里,绘制时只取需要的一段(只要每次的起点不同,自然就动起来了)
5
你可以打印一下绘制函数所用的时间。看看哪个费时把哪个优化下。
30
之所以称之为背景,那么他就是相对不变的
所以可以放在 PictureBox.Image 中,也就不会被 Graphics.DrawXXXX 破坏掉
你动态绘制的都是前景,虽然有些部分是属于背景的,但原因是是动态绘制的,所以仍应归于前景
你本来就是全部绘制的,只不过只在其他地方画好,再复制过来
假如你直接绘制,不就可以省去复制、粘贴(DrawImage)的过程了吗?
你都可以复制、粘贴了,就证明画图本身并没有问题,所以直接画也不会有问题
Graphics.Clip 是绘制时的裁剪区域,你可通过他缩小实际绘制时的区域
扫描该区域涉及到那几个轨道 这的确是个问题,假如你硬是逐像素看短的话,肯定是不可取的,但你可以将轨道保存到 GraphicsPath 中,通过 IsVisible 方法就可轻松的找到点能否在路径中
所以可以放在 PictureBox.Image 中,也就不会被 Graphics.DrawXXXX 破坏掉
你动态绘制的都是前景,虽然有些部分是属于背景的,但原因是是动态绘制的,所以仍应归于前景
你本来就是全部绘制的,只不过只在其他地方画好,再复制过来
假如你直接绘制,不就可以省去复制、粘贴(DrawImage)的过程了吗?
你都可以复制、粘贴了,就证明画图本身并没有问题,所以直接画也不会有问题
Graphics.Clip 是绘制时的裁剪区域,你可通过他缩小实际绘制时的区域
扫描该区域涉及到那几个轨道 这的确是个问题,假如你硬是逐像素看短的话,肯定是不可取的,但你可以将轨道保存到 GraphicsPath 中,通过 IsVisible 方法就可轻松的找到点能否在路径中
5
你不用管数据的刷新率,只定你的软件刷新率就行了,也就是说,不是数据的刷新来引发界面的刷新,是用另一个计时器来实现。
每个点,读取当前的数据状态,然后将有变化的部分绘制出新的图像并且覆盖在指定区域即可。
计时器的速度楼上已经说了,电视、电影都是30FPS左右即可。也就是说,假如你的绘制和刷新速度小于 1/30″,那软件肯定没问题。
每个点,读取当前的数据状态,然后将有变化的部分绘制出新的图像并且覆盖在指定区域即可。
计时器的速度楼上已经说了,电视、电影都是30FPS左右即可。也就是说,假如你的绘制和刷新速度小于 1/30″,那软件肯定没问题。
10
在 Graphic 上 DrawLine( ) 肯定没问题。不会有不连续的跳跃感。
假如数据太多,为了提速还有更加变态的办法,就是尽量减少重绘的区域。你把图形文件分成N个方格。然后在计时器事件上算出哪些方格是有变化的。删除这些方格,然后重绘和它有关的全部数据。这是比较简单的方法。假如速度还不够,就把每个矢量数据分割到这些方格里,每次要更新的时候只画方格里的内容就行。例如,将一条背景上穿过三个方格的线段分割成三条线段,当某个方格需要重绘时,只需绘制它对应的那条线段,而不是整条线段。这样做的好处是速度快,但是代码难度太大。
假如数据太多,为了提速还有更加变态的办法,就是尽量减少重绘的区域。你把图形文件分成N个方格。然后在计时器事件上算出哪些方格是有变化的。删除这些方格,然后重绘和它有关的全部数据。这是比较简单的方法。假如速度还不够,就把每个矢量数据分割到这些方格里,每次要更新的时候只画方格里的内容就行。例如,将一条背景上穿过三个方格的线段分割成三条线段,当某个方格需要重绘时,只需绘制它对应的那条线段,而不是整条线段。这样做的好处是速度快,但是代码难度太大。
5
LZ完全是想多了,根本不用考虑部分的问题,就是整个图像刷新。写一个特定时刻画出整个图像的方法,然后大致估计一下调用这个方法的事件(用datetime记录在日志上),取一个平均值,然后用一个计时器每隔0.02秒调用一次刷新界面就成了,也就是50帧