NCCALCSIZE消息

当WM_NCCALCSIZE消息的WPARAM为TRUE时,这个消息会呈现出它另外一种更加复杂的形式。

在这种情况下,WM_NCCALCSIZE消息的LPARAM参数实际上是指向一个NCCALCSIZE_PARAM结构体的指针。

当Windows发送WM_NCCALCSIZE消息消息时,此结构体会使用如下的方式被填充:

> rgrc[0]: 新的窗口矩形(在父窗口坐标系下)

> rgrc[1]: 旧的窗口矩形(在父窗口坐标系下)

> rgrc[2]: 旧的客户区矩形(在父窗口坐标系下)

请注意,上面的客户区矩形是以父窗口坐标作为参考坐标系,而不是客户区的坐标系。

当WM_NCCALCSIZE消息的处理例程准备返回的时候,Windows会期望NCCALCSIZE_PARAM结构体以如下的方式被填充:

> rgrc[0]: 新的客户区矩形(在父窗口坐标系下)

新的客户区矩形指明了在新的窗口矩形中,窗口的客户区将如何在窗口矩形中被定位。

更进一步地,如果你的消息处理例程返回0以外的值,则Windows还会期望NCCALCSIZE_PARAM结构体的剩下两个成员以如下的方式被填充:

> rgrc[1]: 目标矩形(在父窗口坐标系下)

> rgrc[2]: 源矩形(在父窗口坐标系下)

(如果你返回的是0,则Windows会认为目标矩形和新的客户区矩形相等,并且源矩形和旧的客户区矩形相等)。

源矩形和目标矩形指明了旧窗口的哪一部分对应了新窗口的哪一部分。Windows将会从源矩形中拷贝所有像素到目标矩形并保持它们的有效性。

WM_NCCALCSIZE消息的返回值表示的意思是:如果两个矩形(源矩形和目标矩形)不相等,应该如何处理这两个矩形的像素差别。默认的处理方式是从矩形的左上角对齐这两个矩形。

接下来,让我们来使用一个全新的例子来演示一下自定义的矩形的情况。(我们后面还是会回到之前的滚动条的系列程序)。

首先,下面的帮助函数会计算一个矩形的中心位置。

更加深入的理解WM_NCCALCSIZE消息

练习题:为什么我们在上面的帮助函数中使用c = a + (b – a) /2 这个公式,而不是使用更为简单的c = (a + b) / 2呢?

下面是我们的PaintContent函数:

更加深入的理解WM_NCCALCSIZE消息

当我们调试界面闪烁的问题的时候,故意地绘制一个很显眼的背景色并添加一些手动的暂停可能会非常有帮助,因为这样你可以清楚地看到绘制过程是如何进行的。

但是,需要注意的是,当你准备这样做的时候,需要调用GdiSetBatchLimit来禁止GDI批处理。否则,GID将会优化掉所有的重复填充操作,这样的话,你就不会具体的绘制过程。

真正起作用的是我们的WM_NCCALCSIZE消息处理例程:

更加深入的理解WM_NCCALCSIZE消息

上面的代码会如何工作呢?

如果fCalcValidRects为TRUE,我们将会通过查看窗口的内容需要偏移多少来计算有效的矩形,然后将有效的目标矩形移动相同的偏移量。用户将有效源矩形的左上角拷贝至目标矩形的左上角,因此,将目标矩形的左上角进行偏移让我们可以调整用户拷贝的部分。

可以这样进行测试: 拖动窗口并尝试调整窗口的大小。我们可以观察到:窗口客户区的中心部分从窗口的原始位置上被拷贝且没有被重绘。

这样会带来两种好处:第一,没有出现界面闪烁的情况。二是,优化了绘制性能,因为我们并没有进行非必要的像素绘制。

上面提到的第二个好处特别重要,因为当我们使用远程桌面时,客户端需要在网络上传输所有需要绘制的像素,需要传输的像素越少,则远程桌面使用起来会更加流畅。

现在,我们对WM_NCCALCSIZE消息有了更加深入地理解了,我们可以利用它来优化我们的滚动条程序了。

更加深入的理解WM_NCCALCSIZE消息


分享到:


相關文章: