窗口属性 客户矩形_优化点:仅当窗口在屏幕上可见时才进行绘制

有这么一个需求

有时候你会想执行这样一个任务:当窗口没有被另一个窗口覆盖时,对这个窗口执行某个动作,例如更新一个状态窗口。

任务栏如何更新时钟

检测一个窗口是否可见的最简单的方法,就是不对它进行检测。举个例子,下面是任务栏是如何更新它的时钟的:

1. 计算距离下一次分钟更新还需要多长时间。

2. 使用步骤[1]中得到的结果来调用[SetTimer]创建一个定时器。

3. 当计时器超时,它会调用[InvalidateRect]并销毁定时器。

4. [WM_PAINT]消息处理例程会绘制当前时间到任务栏的时钟控件上,然后重返步骤[1]。

如果任务栏的时钟由于任务栏本身被设置为自动隐藏,或者它被其他窗口覆盖了而呈现出不可见的状态时,Windows将不会向窗口发送[WM_PAINT]消息,因此,任务栏时钟将会进入空闲状态同时不会消耗任何CPU时间。根据以上的原理,我们可以对我们的程序应用相同的逻辑。

在下面的代码中,我们的程序将会显示当前时间。同时,它还会将时间显示在窗口的标题栏,因此当窗口被覆盖或者最小化时,我们可以借助于观察任务栏来查看窗口的绘制行为。

代码如下:

88853f0941c5e355dfc7606759e4284c.png

下面的代码是一个定时器的回调函数,当我们希望更新窗口时,这个回调函数将会被调用。它仅仅是销毁定时器并将窗口绘制区域无效化。当窗口下一次恢复可见时,我们会得到一个[WM_PAINT]消息。(如果当窗口立即变得可见时,我们也会立即得到一个[WM_PAINT]消息)

cb7f3b635193700c90ddff072552d0c2.png

最后,我们在WM_PAINT消息处理例程中添加了一些代码,这样每次当我们绘制了一个非空的矩形时,重启定时器。

下面是WM_PAINT消息处理例程:

42067a6ef73a6b0933013c78635ba499.png

编译并运行这个程序,我们可以观察到时间会正常的更新。当你最小化窗口或者这个窗口被其他窗口覆盖时,时间更新停止了。当你拖动窗口到屏幕底部直到只有标题栏可见时,我们会观察到窗口时间的更新也会停止。为什么呢?因为WM_PAINT消息处理例程是用来绘制客户区的,在这种情况下,客户区已经不在屏幕上了。

当你切换到其他用户或者锁定计算机时,窗口也会停止更新时间,虽然在这种情况下你会看不到任务栏来验证这个说法。但是,你可以使用计算机的扬声器来进行验证:在[PaintContent]中改为调用[MessageBeep]来发出声音,这样每当时间被重新绘制时,你都会听到一次扬声器的响声。当切换到其他用户或者锁定计算机时,我们不会听到这个声音,也即证明了之前我们的说法。

仅绘制我们希望绘制的区域,而不是全部

这种无效区绘制的手法,同样可以被扩展到屏幕上只有一块区域需要绘制的情景:仅仅绘制你希望绘制的区域,然后仅当这个区域是待绘制区域的一部分的时候才重启定时器,而不是绘制整个客户区。

下面是我们需要作出的代码改动:

cf644dd19b8f3159379067f1336cb353.png

当定时器到期,我们仅仅更新上面定义的区域,而不是整个客户区(作为一个优化措施,我禁用了背景,后面我会提到我为什么这样做)。

b6909a8d61df2cc81133ce20cf7c8cd6.png

为了更加清楚的显示这个目标绘制区域,我们高亮的绘制了这个区域并在里面显示时间。通过使用[ETO_OPAQUE]标志,我们同时绘制了前景和背景。因此,我们不需要再让它为我们擦除背景了。

272f538d49e779a34b01b52c45b82258.png

最后,在WM_PAINT消息处理例程中的代码需要检查目标绘制区的可见性,而不是使用整个客户区。

2f4d315cc643f02fd2fb1427149437d6.png

运行这个程序的时候,我们可以使用一些方法来覆盖窗口或者禁止高亮区域的绘制。我们可以观察到:一旦窗口被覆盖,标题栏就停止更新了。

总结

就像我上面说过的,这项技术对于大多数应用程序来说已经足够了。但是还有另外一种更加复杂(也更加昂贵)的技术,我将会在下周为大家揭秘。

b175c6eee3e29305ce8ef2c239bcf5c9.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值