一、MFC的消息類型
MFC的消息類型大致可以分為三種:
1.命令消息。由菜單和工具欄或快捷鍵產生,以WM_COMMAND形式發出(以WM_COMMAND發出的還有很多控件,如Button等,但它們產生的不是命令消息,是通知消息)
命令消息的消息宏是:ON_COMMAND(id,memberFxn)。
2.窗口消息。由系統產生,典型特征是以WM_開頭(WM_COMMAND除外)。此類消息映射宏前綴為“ON_WM_”,並且沒有參數,因為不管是消息本身還是響應函數都與WM_XXX一一對應了。
3.通知消息。這類消息類型很多,也是最麻煩的。通常以WM_COMMAND或WM_NOTIFY形式發送。通知消息是由子控件發送給父窗口的。
WM_COMMAND形式是為了兼容以前的格式,因為MFC4.0之前都是以命令消息當作通知消息傳遞,后來子控件增多,不夠用,所以增加了WM_NOTIFY,但為了向前兼容,仍然保留了WM_COMMAND消息,所以制造可麻煩。
父窗口處理通知消息的消息宏因此就分為兩類:
WM_COMMAND形式的:ON_CONTROL(wNotifyCode,id,memberFxn)或ON_CONTROL_RANGE(wNotifyCode,id,idLast,memberFxn),該宏擴展后發現第一個參數就是WM_COMMAND。所以說ON_CONTROL宏是為了向前兼容的老用法了。
WM_NOTIFY形式的:ON_NOTIFY(wNotifyCode,id,memberFxn)或ON_NOTIFY_RANGE(wNotifyCode,id,idLast,memberFxn),該宏擴展后發現第一個參數就是WM_NOTIFY。
但是通常我們很少看到這兩個宏,而是被類似ON_BN_CLICKED(id,memberFxn)這樣的替換了。實際上這也是一種宏,這種宏展開后還是使用了ON_CONTROL或者ON_NOTIFY宏。只是把參數一wNotifyCode通知碼改變成了更容易理解的BN_CLICKED罷了。
通知消息的一個很重要的特性是反射機制。只有繼承CWnd的類有反射機制,通知消息有反射機制,占大多數,但其它有的消息也具有反射性,因為消息反射性的存在主要是為了方便改變子控件本身的某種特性,因此如WM_CTLCOLOR也具有反射性。查看某個消息是不是具有反射性,只需進入類向導中查看消息選項內部,該消息前有沒有=號,有則代表有反射性。
反射機制的工作原理是:子控件產生通知消息后,首先發送給父窗口,讓父窗口先處理。但是如果子窗口也具有處理該通知消息的能力,父窗口就將該消息返回給子窗口處理(即子窗口有優先處理自身消息的能力),如果子窗口處理后,消息結束,不再發給父窗口。否則,如果子窗口不具備處理該消息的能力,那么父窗口來處理,如果父窗口也無法處理,再往上拋,直到被處理或拋棄為止。
但是如果子窗口處理后,還想讓父窗口處理,那么子窗口處理函數最后一定要reurn FALSE表示該消息沒有被處理(實際上已經處理了),讓父窗口接着處理。
那么子窗口處理這種反射回的信號的宏是什么呢?
就是ON_CONTROL_REFLECT_EX(wNotifyCode,memberFxn)和ON_NOTIFY_REFLECT_EX(wNotifyCode,memberFxn),memberFxn的返回值是BOOL,要改過來。
最后講一講通知碼的問題:
參數wNotifyCode就是通知碼,它標識着子控件發生了什么(比如按鈕是被點擊(BN_CLICKED)了,還是雙擊(BN_DOUBLECLICKED)了,還是失去焦點(BN_KILLFOCUS)),也可以看成消息,但是與WM_LBUTTONDBLCLK不是一回事,前者是通知消息的參數是告訴父窗口子窗口被雙擊了,后者是不需要告訴父窗口的,子窗口可以自己進行處理的消息)
還有一類宏是負責菜單項等是否可用的,下次再講。
總之:
1.本文最主要的目的是讓人看到消息映射宏后知道處理的是哪種類型的消息;
還有個問題就是為什么按鈕的消息響應函數寫在父窗口類中?
原因很簡單,因為按鈕是子控件,子窗口其實有處理通知消息的優先權,但是一般它不處理(除非你重載),所以就交給父類處理了。本來通知消息也是首先發送給父類的,只是父類又返回給了子控件,這樣做是為了強調父窗口的控制權威。就跟很多事情基層做報告,報告拿到上級批准了,才允許執行一樣,其實報告本身還是基層做的,只是顯示了上級的權威性,控制性。