C#在PictureBox中绘图防止闪烁的办法

C#在PictureBox中绘图防止闪烁的办法


2024年7月3日发(作者:)

C#在PictureBox中绘图防止闪烁的办法

展开全文

很久没发技术文章了啊……被人说装文艺了啊……我在乱说些啥

吗…………

最近学校开了数据结构的课设设计,说是允许使用C++,Java和

C#来进行开发。Java上上个学期学的,说实话,感觉真的不是很

爽……或许是我电脑的缘故,也或许是心理作用,我总觉的NetBeans

一开就卡得不行!无论怎样都得不到在VS中开发和调试的那种爽快感,

于是一度打算投奔C++的阵营,还为此买了Qt的书来学习,不过由

于一直以来被诸多事情所扰(懒?),Qt的学习就停留在了……编译

完毕。好吧,我输了……C#,就决定是你了!

那么进入正题吧。

在课程设计的过程中,我需要在窗体上进行图片的绘制,但是在

实际的测试中发现了问题,那就是重绘的时候会发生闪烁,这个问题

其实在大一的C语言课设的时候就出现过了,在程序绘制动画的高频

率刷新的时候,也会产生闪烁,而那时候的解决办法,是对动画进行

双缓冲(Double Buffering)处理。

在被双缓冲这个名词吓到之前,我们先来探讨下为什么重绘的时

候会发生闪烁:

说道动画的原理大家都懂,就是利用了人眼的视觉残留(Visual

staying)现象,当一副画面进入人眼成像后,并不会立刻消失,而是

仍会保留一小段时间,于是当连续的图像以很高的速度切换的时候,

人眼会看到动态的影响,而不是处于切换中的单个图像。

这个过程可以参考图1:

当这三幅图片以一定频率直接切换的时候,人们就会看到A貌似

是在像右方移动。

那么为什么我们依据这个原理来编程绘制动画的时候会出现闪烁

呢?是因为计算机的速度太慢不够给力么?当然不是!

我们如果不加任何处理,就在画布C上进行绘图,那么计算机的

处理过程是这样的:

Step 1: 将C以背景色填充(也就是清除

C上现有的内容)

Step 2: 在C上按照要求绘制新的画面

那么这样的过程会对动画产生怎样的影响呢?请看图2:

了空白的画面,这个空白的画面由于和人眼中原本残留的图像反差非

常大,所以便会破坏视觉残留产生的动画,给人的感觉就是,这个动

画在不停的闪烁。

看出和图1的差别了吧?Step1相当于在原本连续的动画中嵌入

于是我们现在知道消除Step 1这个过程带来的影响,就能够避免

在绘制的时候发生闪烁,不知道你会不会想,直接把Step 1略过不就

得了?但我可以很负责任的告诉你……不行!如果只是单纯的略过

Step 1,那么动画就会变成这样:

在视觉上就成了一个拖着残像尾巴运动的动画,相信大家一定见

过这个:

那么我现在就可以解释双缓冲是怎样防止闪烁的了。

假如我们希望在屏幕S上展示动画,首先我们需要在内存中建立

一个虚拟的画布C,然后我们所有的绘图操作都在C上进行,当绘制

动画的一帧完毕后,我们啪唧~把C直接往S上一拍,这样就既不会出

现拖尾巴,也不会出现Refresh时的短暂空白了,如下图所示,红色

的框就代表那块虚拟的画布:

原理我们都知道了,但是实际应用的时候还是会遇到一些问题,

这些问题涉及到C#本身的窗体的绘制机制,不过我们还是能够解决的。

当我们通过这种方法在pictureBox上绘图的时候,特别是

pictureBox还存在背景图片的时候。我们就会遇到问题:

C#

// 初始化画板Bitmap image = new

Bitmap(,

);// 初始化图形面板Graphics g =

age(image);// 绘图部分 Begin// ... ...// 绘图部分

Graphics().DrawImage(image, 0, 0);

画布g是透明的,所以在g上绘制后,贴在pictureBox上,背景

图片还是会展示出来,但是问题也就来了,由于pictureBox的绘制机

制问题,如果我在pictureBox上贴一张透明的图,其效果就是这样的:

不知道读者明白这是什么意思了么……如果将透明的图片贴上去,

那其实和直接略掉刚才所说的Step 1别无二异!如果我们想要将之前

的内容去除,就不得不再使用h()方法,而这样的

话,显然会导致闪烁,那么该怎么办呢?

网上搜索了很多,也有很多方法,比如将窗体的Double

Buffered属性设置为true,或者通过继承或者反射机制,将

pictureBox的Double Buffered属性设置为true,但是经过实验,这

些方法都不大灵光。于是我开始静下心来思考该怎么绕过这个问题。

其实理清思路后就会发现,我们这个问题所遇到的障碍就是不能

影响pictureBox的背景图的展示,所以我们为何不把pictureBox的

背景图片也提取出来,作为底层画布呢?

下面是我给出的解决方案:

C#

// 初始化画板Bitmap image = new Bitmap(,

);

// 获取背景层Bitmap bg = (Bitmap)oundImage;

// 初始化画布Bitmap canvas = new

Bitmap(, );

// 初始化图形面板Graphics g = age(image);Graphics gb

= age(canvas);

// 绘图部分 Begin// ... ...// 绘图部分 End

age(bg, 0, 0); // 先绘制背景层age(image, 0, 0); //

再绘制绘画层

oundImage = canvas; // 设置为背景层

h();Graphics().DrawImage(canvas

, 0, 0);

注意我标注的行,就是添加的部分。

pictureBox的Refresh()方法不会影响其背景层,所以我们将最后

合成的画布直接贴在背景层上,这样再Refresh()就不会产生闪烁了,

同时,由于系统会自动重绘背景层,所以在窗口最小化或者被遮挡过

后,绘制的图像也不会消失,相当同时于免去了手动重绘之苦。这样

一来,困扰我们的闪烁问题就彻底的被解决啦!

感觉自己不知不觉废了好多话呀……啦啦啦,这篇就到这喽。


发布者:admin,转转请注明出处:http://www.yc00.com/news/1719964012a2759447.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信