最近在看《Windows程式設計》一書,其間發現一個小細節:
1. 在非活動表單上單擊滑鼠時,Windows將使該表單成為活動表單,然後向其發送WM_LBUTTONDOWN訊息。
2. 單擊表單上的某一控制項時,該控制項收到WM_LBUTTONDOWN,但Windows不會使該控制項成為焦點控制項,而需要程式調用SetFocus來使其獲得焦點。
一個事實是,對Windows而言,所有UI元素都是視窗。控制項也是視窗,只不過它是主視窗的子視窗;而主視窗同樣可以視為Windows的子視窗。
那麼,這個處理上的差異暗示了什麼呢?
我把這個問題發到CSDN,過了一星期也沒得出個所以然。
然而我剛剛想明白了,這個處理上的差異實際上是以下設計思路的體現:
1. 頂級表單間的切換由Windows控制。
2. 表單中的控制項間的焦點切換由應用程式控制。
在Windows中,應用的單元是進程(或者線程、表單)。
一個應用程式對外是一個整體,表單中的控制項焦點的切換可視為內部行為,因此Windows不予幹涉。
應用程式(視窗)間屬於平等和競爭(輸入)的關係,因此,活動表單的切換不能由應用程式控制,而應由Windows進行控制。
根據這個思路,此差異便容易理解了。
在使用者期望中,他們希望能夠對可見的所有表單執行滑鼠操作,而不論其是否處於活動狀態;另外,使用者還會希望通過滑鼠點擊非活動表單來使表單進入活動狀態從而能夠接收鍵盤輸入。因此,Windows的響應便為:先使其轉入活動狀態,再向其發送滑鼠訊息。
對於表單中的控制項,我們也許認為Windows可以把控制項收到滑鼠訊息後自動獲得焦點作為一個預設行為。這聽起來似乎符合我們的常規邏輯,但實際上不然,控制項分為“輸入”和“非輸入”兩類,我們只留意到輸入性的控制項,例如ComboBox、Text等;而忽略了非輸入性的靜態控制項,也就是Label。由於控制項是否應在按一下滑鼠後獲得焦點在很大程度上是由控制項的性質決定的。因此,此邏輯最適於放置在控制項的視窗過程中。