在類的體系結構中,框架程式提供了cwnd類來封裝視窗的hwnd控制代碼,即使用cwnd類來管理視窗的物件,這包括視窗的建立和銷
毀、視窗的一般行為和視窗所接收的訊息。
ccmdtarget類:
為了使其它的類也有處理訊息的機會,我們封裝乙個類ccmdtarget作為訊息處理的終點,即所有從這個類派生的類都有處理訊息的能
力。所有有訊息處理能力的類都要從ccmdtarget繼承。
cwnd和ccmdtarget都定義在標頭檔案 中。
ccmdtarget的部分結構如下:
class afx_novtable ccmdtarget : public cobject
;
cwnd的部分結構如下:cwnd類的實現**在wincore.cpp檔案中。
class cwnd : public ccmdtarget
;
乙個執行緒中可能有不止乙個視窗,因此也會有多個對應的cwnd物件,每個cwnd物件只響應傳送給本視窗的訊息。
執行緒如何將接受到的訊息交給不同的cwnd物件?
windows是通過視窗函式將訊息傳送給應用程式的,視窗函式的第乙個引數hwnd指示了接收此訊息的視窗,我們只能通過視窗控制代碼
1.只安排乙個視窗函式;這裡的視窗函式的作用僅僅是找到處理該訊息的cwnd物件的位址,再把它交給此cwnd物件。解決上面問題的另一種方法:使用chandlemap類2.記錄視窗控制代碼到cwnd物件指標的對映關係。
windows為每乙個執行緒維護乙個訊息佇列。視窗控制代碼對映是模組執行緒私有的,所以我們將記錄了視窗控制代碼對映的chandlemap物件定義 在
模組執行緒狀態類 afx_module_state中。
cwnd類提供4個成員函式來管理視窗控制代碼對映,這些函式都是先呼叫afxmaphwnd函式得到chandlemap指標。
1. fromhandle(hwnd hwnd):試圖返回指向cwnd物件的指標,
2. fromhandlepermanent(hwnd hwnd)
3. attach(hwnd hwndnew): 新增一對對映項
4. detach(): 移除一對對映項
每建立乙個視窗,就呼叫attach函式將新的視窗控制代碼附加到cwnd物件,在此視窗銷毀的時候再呼叫detach函式取消上面的附加行為。
這樣,在整個視窗的生命週期內,就會存在乙個此視窗控制代碼hwnd 到 cwnd物件指標pwnd的對映項。
接下來就是怎麼處理訊息了,,,,,,
訊息處理函式中可以這樣寫:
cwnd * pwnd = cwnd::fromhandle(hwnd);
return pwnd->windowproc(nmsg, wparam, lparam);
直接在視窗函式wndproc中處理訊息很繁瑣,我們希望能夠直接使用類的成員函式響應感興趣的訊息。訊息和處理訊息的成員是一一
對應的,這就是所謂的訊息對映。每一對訊息和處理訊息的成員組成乙個對映項,類中所有的對映項連在一起形成訊息對映表。
訊息對映項:每個訊息對映項最基本的內容應該包括訊息的值和處理該訊息的成員函式。 用結構 afx_msgmap_entry 來描述它。
struct afx_msgmap_entry
;
typedef void (ccmdtarget::*afx_pmsg)(void); 在這裡,為什麼要把訊息處理函式都定義成ccmdtarget類的成員函式?
所有有消
息處理能力的類都要從ccmdtarget繼承,因為無法預知使用者定義的訊息處理函式的具體型別,所以只好先統一轉化成afx_pmsg
巨集指定的型別。
要想自己的類有處理訊息的能力,就必須從ccmdtarget類繼承,而且還必須有自己的訊息對映表,這就要求記錄下其基類中的訊息映
射表的位址(這樣訊息才能向上傳遞)。
struct afx_msgmap
;
幾個巨集的定義:在中
1.declare_message_map:宣告訊息對映
#define declare_message_map() \
protected: \
static const afx_msgmap* pascal getthismessagemap(); \
virtual const afx_msgmap* getmessagemap() const; \
訊息對映表中記錄的資料是由使用者填寫的,為了方便使用,我們用begin_message_map 和 end_message_map 兩個巨集代替
實現訊息對映的**
2.begin_message_map:
#define begin_message_map(theclass, baseclass) \
ptm_warning_disable \
const afx_msgmap* theclass::getmessagemap() const \
\const afx_msgmap* pascal theclass::getthismessagemap() \
來表示陣列的
結束。#define end_message_map() \
\}; \
static const afx_msgmap messagemap = \
; \return &messagemap; \
} \
ptm_warning_restore
begin_message_map 和 end_message_map必須配對使用,例如:
begin_message_map(cmywnd, ccmdtarget)
, ,
, end_message_map
怎麼給類庫中的類新增訊息對映表?後面還會講到怎麼新增訊息對映項。
很簡單,只需在類的定義**中加入declare_message_map 巨集,就可以新增訊息對映表。例如:
class ccmdtarget: public cobject
;
因為ccmdtarget類位於訊息對映的最頂層,所以不能直接用begin_message_map 和 end_message_map這一對紅,而只
能手工新增訊息對映的**。
windows統一用wparam 和 lparam 兩個引數來描述訊息的附加資訊。cwnd物件的windowproc函式在呼叫訊息對映表中的函式
響應windows訊息時,它如何知道向這個函式傳遞什麼引數呢?又如何知道該函式是否有返回值呢? 所以,在訊息對映項中還要記
錄下函式的型別。
afx_msgmap_entry結構中的nsig成員用來記錄函式的型別。
框架視窗的建立
構造cframewnd視窗三種途徑 1 使用create函式直接構造 2 使用loadframe函式直接構造 3 通過文件模板直接構造 在使用create或loadframe之前,必須使用c new操作符在堆中構造框架視窗物件。在呼叫create函式之前,必須使用afxregisterwndclas...
透明框架視窗
如何讓整個視窗具有透明效果呢?使用如下的類 class clayeredimpl layered window template class atl no vtable clayeredimpl virtual clayeredimpl long setlayeredstyle bool setla...
視窗關係以及框架
top物件 始終指向最高 最外 層的框架,也就是瀏覽器視窗。window物件 指向的是哪個框架的特定例項。parent 父 物件 始終指向當前框架的直接上層框架。self物件 始終指向window,實際上,self和window物件可以互換使用。所有這些物件都是window物件,可以通過window...