导致画面闪烁的关键原因分析:
一、绘制窗口由于大小位置状态改变进行重绘操作时
绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。
所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。
根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。
解决上述问题的关键在于:窗口刷新一次的过程中,让所有图元同时显示到窗口。
二、进行鼠标跟踪绘制操作或者对图元进行变形操作时
当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁现象并不能完全消除!
所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。
解决此问题的关键在于:设置窗体或控件的几个关键属性。
你把你要画的东西先画到一个内存的image里,这个image可以创建一个Graphics,就按你原来画的方法在这个graphics上画
最后,把这个image画到你原来的graphics上
1、在内存中建立一块“虚拟画布”:
Bitmap bmp = new Bitmap(600, 600);
2、获取这块内存画布的Graphics引用:
Graphics g = Graphics.FromImage(bmp);
3、在这块内存画布上绘图:
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
4、将内存画布画到窗口中
this.CreateGraphics().DrawImage(bmp, 0, 0);
===========================================================================
这里说明一下:
1、this.CreateGraphics()实际上是获得一个基于当前窗体的Graphics对象,此外我们还可以创建基于控件的Graphics,比如说基于窗体中的Panel:this.FramePanel.CreateGraphics()。基于控件创建的Graphics只针对于当前的控件进行绘制操作,不会影响到其他的控件状态。
2、除了针对可见的控件(实质上就是显存了)创建Graphics之外,我们还可以针对普通内存进行创建。比方说像第二步中那样,先在内存中申请一个Bitmap对象,针对该对象创建Graphics。由于新创建的Graphics针对于内存,所以第三步对其上附加的Bitmap绘制时,不会马上显示到屏幕(即不会刷屏)。等到第四步将其绘制到窗口之前,Bitmap里已经是完好的图像数据了,因此不会出现刷屏的现象。
3、你可以将Graphics想象成是一个画夹,将附加于其上的内存或是显存想象成画纸。画纸必须先附加到画夹上,才可以用工具进行绘制。
4、Graphics的使用其实非常类似于MFC中的CDC,具体的用法请参看MSDN。
==============================================================================
还有的方式
在构造函数中加如下代码
代码一:
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
代码二:
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();
一、绘制窗口由于大小位置状态改变进行重绘操作时
绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。
所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。
根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。
解决上述问题的关键在于:窗口刷新一次的过程中,让所有图元同时显示到窗口。
二、进行鼠标跟踪绘制操作或者对图元进行变形操作时
当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁现象并不能完全消除!
所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。
解决此问题的关键在于:设置窗体或控件的几个关键属性。
你把你要画的东西先画到一个内存的image里,这个image可以创建一个Graphics,就按你原来画的方法在这个graphics上画
最后,把这个image画到你原来的graphics上
1、在内存中建立一块“虚拟画布”:
Bitmap bmp = new Bitmap(600, 600);
2、获取这块内存画布的Graphics引用:
Graphics g = Graphics.FromImage(bmp);
3、在这块内存画布上绘图:
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
4、将内存画布画到窗口中
this.CreateGraphics().DrawImage(bmp, 0, 0);
===========================================================================
这里说明一下:
1、this.CreateGraphics()实际上是获得一个基于当前窗体的Graphics对象,此外我们还可以创建基于控件的Graphics,比如说基于窗体中的Panel:this.FramePanel.CreateGraphics()。基于控件创建的Graphics只针对于当前的控件进行绘制操作,不会影响到其他的控件状态。
2、除了针对可见的控件(实质上就是显存了)创建Graphics之外,我们还可以针对普通内存进行创建。比方说像第二步中那样,先在内存中申请一个Bitmap对象,针对该对象创建Graphics。由于新创建的Graphics针对于内存,所以第三步对其上附加的Bitmap绘制时,不会马上显示到屏幕(即不会刷屏)。等到第四步将其绘制到窗口之前,Bitmap里已经是完好的图像数据了,因此不会出现刷屏的现象。
3、你可以将Graphics想象成是一个画夹,将附加于其上的内存或是显存想象成画纸。画纸必须先附加到画夹上,才可以用工具进行绘制。
4、Graphics的使用其实非常类似于MFC中的CDC,具体的用法请参看MSDN。
==============================================================================
还有的方式
在构造函数中加如下代码
代码一:
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
代码二:
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();