彻底解决窗口闪烁问题

引言

在绘制只自定义控件和画图时,倘若我们执行改变窗体大小等频繁激发窗体WM_PAINT事件的操作时,会发现自定义的控件会发生闪烁的情况,这很容易给人带来不专业的感觉,笔者经过研究发现了其中的问题所在,在此撰写成文,供大家参阅。

网上的类似文章

笔者在网上也搜索过很多类似问题的解决方法,其中方法大多归为如下几类:

1、注册窗体类时去掉CS_VREDRAW 和 CS_HREDRAW

2、在内存中存储一个图,然后使用 BitBlt 一次性贴到目标 DC 上

3、创建父窗口时加上 WS_CLIPCHILDREN 来避免重绘被子窗体该住的地方等等

方法确实很多,但是经过笔者的实践与思考,发现者都不是解决问题的最好方法,那么问题究竟出现在哪里呢?

问题所在

闪烁,仔细观察就能发现使图像频繁的被擦除和绘制,又因为背景和所要绘制的图像差别较大,且擦除原有图像时要更新显示区域,这样我们就能看到背景,然后马上又要用新图像盖掉背景,这就是闪烁的根本原因,其实这个过程很慢,我们的人眼已经能识别出来了。但是WS_CLIPCHILDREN仍然是必要的。

解决问题

解决问题的思想很简单:不擦除背景,用新图直接覆盖原图

这里有一点是值得注意的:笔者实践中感觉最理想的办法就是生成一张和Client area 大小相同的图去填充Client area,这张图中可能包含背景,例如:此处只以将c 显示在窗口左上角为例,下标默认为0

假设我要显示的图片 s 大小为 M * N, Client Area 的大小为 A * B,其中 A > M 或 B > N。

依照本文方法,给出如下数学语言的表示(别怪我啊,我是学数学的啊,这样比较舒服):

1、内存中生成一张大小为 A * B 的位图 c

2、当且仅当 y >= M 或 x >= N 时 c(x, y) = 背景色, 否则,c(x, y) = s(x, y)

注:c(x, y) 表示图像 c 的第 y 行,第 x 列的像素值,s(x, y)表示图像 s 的第 y 行,第 x 列的像素值。

解决问题中遇到的问题

如何控制程序不擦除背景?

这就要摸索一下Windows的消息机制了,不仅仅是它的思想,而是它的消息传递次序上面可能有我们没有研究过的地方。

系统在向窗体发送 WM_PAINT 之前首先会向窗体发送 WM_ERASEBKGND 消息告诉窗体消息处理函数,让它擦除窗体上的图像 = 用背景色覆盖当前窗体。

这样,我们的解决方法就出来了,拦截 WM_ERASEBKGND 消息, 并在处理消息的时候 do nothing,问题就没有了。

深层次讨论

1、前面有一点要补充的就是,窗体的背景色是在注册窗体类时 hbrBackground 属性指定的,如果你设置此属性为 NULL,那么你就必须手动处理 WM_ERASEBKGND。

2、注意:如果我们在窗体上放置了滚动条,那么我们在操作滚动条的时候一定要记得重画滚动条,比如SetScrollPos, SetScrollRange 等等都有一个参数是用来标示是否要重画滚动条的,设置成TRUE就可以了,当然这不仅仅局限于滚动条,比如状态栏什么的,大家举一反三就可以了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值