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消息


分享到:


相關文章: