TN061:ON_NOTIFY 和 WM_NOTIFY 訊息
注意
下列技術提示自其納入線上文件以來,未曾更新。 因此,有些程序和主題可能已過期或不正確。 如需最新資訊,建議您在線上文件索引中搜尋相關的主題。
此技術附注提供新WM_NOTIFY訊息的背景資訊,並說明在 MFC 應用程式中處理WM_NOTIFY訊息的建議(和最常見)方式。
Windows 3.x 中的通知訊息
在 Windows 3.x 中,控制項會藉由傳送訊息給父系,以通知其父代事件,例如按一下滑鼠、變更內容和選取專案,以及控制背景繪製。 簡單通知會以特殊WM_COMMAND訊息傳送,其中包含通知碼(例如BN_CLICKED),以及封裝在 wParam 中的控制項識別碼,以及控制項在 lParam 中的 控制碼。 請注意,由於 wParam 和 lParam 已滿,因此無法傳遞任何其他資料 , 這些訊息只能是簡單的通知。 例如,在BN_CLICKED通知中,按一下按鈕時,無法傳送滑鼠游標位置的相關資訊。
當 Windows 3.x 中的控制項需要傳送包含其他資料的通知訊息時,它們會使用各種不同的特殊用途訊息,包括WM_CTLCOLOR、WM_VSCROLL、WM_HSCROLL、WM_DRAWITEM、WM_MEASUREITEM、WM_COMPAREITEM、WM_DELETEITEM、WM_CHARTOITEM、WM_VKEYTOITEM等等。 這些訊息可以反映回傳送它們的控制項。 如需詳細資訊,請參閱 TN062:Windows 控制項 的訊息反思。
Win32 中的通知訊息
針對 Windows 3.1 中存在的控制項,WIN32 API 會使用 Windows 3.x 中使用的大部分通知訊息。 不過,Win32 也會將一些複雜的複雜控制項新增至 Windows 3.x 中支援控制項。 這些控制項經常需要傳送其他資料及其通知訊息。 WIN32 API 的設計者選擇只新增一則訊息,WM_NOTIFY,以標準化的方式傳遞任何數量的額外資料,而不是為每個需要額外資料 WM_ * 的新 通知新增訊息。
WM_NOTIFY訊息包含在 wParam 中 傳送訊息之控制項的識別碼,以及 lParam 中 結構的指標。 這個結構是 NMHDR 結構,或是具有 NMHDR 結構做為其第一個 成員的較大結構。 請注意,由於 NMHDR 成員是第一個,因此此結構的指標可以做為 NMHDR 的指標 ,或做為較大結構的指標,視您轉換的方式而定。
在大部分情況下,指標會指向較大的結構,而且當您使用它時,將需要轉換它。 在少數通知中,例如常見的通知(其名稱開頭 為 NM_ ),以及工具提示控制項的TTN_SHOW和TTN_POP通知,是 實際使用的 NMHDR 結構。
NMHDR 結構或初始成員包含傳送訊息和通知碼之控制項的控制碼和識別碼(例如TTN_SHOW)。 NMHDR 結構的格式 如下所示:
typedef struct tagNMHDR {
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
針對TTN_SHOW訊息,程式 代碼 成員會設定為 TTN_SHOW。
大部分的通知都會將指標傳遞至包含 NMHDR 結構做為其第一個 成員的較大結構。 例如,請考慮清單檢視控制項LVN_KEYDOWN通知訊息所使用的結構,這會在清單檢視控制項中按下按鍵時傳送。 指標指向 LV_KEYDOWN 結構,其定義如下:
typedef struct tagLV_KEYDOWN {
NMHDR hdr;
WORD wVKey;
UINT flags;
} LV_KEYDOWN;
請注意,由於 NMHDR 成員是此結構中的第一個成員,因此您傳入通知訊息的指標可以轉換成 NMHDR 的指標 或LV_KEYDOWN 的 指標。
所有新 Windows 控制項通用的通知
某些通知適用于所有新的 Windows 控制項。 這些通知會將指標傳遞至 NMHDR 結構。
通知程式碼 | 已傳送 ,因為 |
---|---|
NM_CLICK | 使用者按一下控制項中的滑鼠左鍵 |
NM_DBLCLK | 使用者按兩下控制項中的滑鼠左鍵 |
NM_RCLICK | 使用者按一下控制項中的滑鼠右鍵 |
NM_RDBLCLK | 使用者按兩下控制項中的滑鼠右鍵 |
NM_RETURN | 使用者按下 ENTER 鍵,而控制項具有輸入焦點 |
NM_SETFOCUS | 控制項已獲得輸入焦點 |
NM_KILLFOCUS | 控制項已失去輸入焦點 |
NM_OUTOFMEMORY | 控制項無法完成作業,因為沒有足夠的記憶體可用 |
ON_NOTIFY:處理 MFC 應用程式中的WM_NOTIFY訊息
函式 CWnd::OnNotify
會處理通知訊息。 其預設實作會檢查訊息對應,以取得要呼叫的通知處理常式。 一般而言,您不會覆寫 OnNotify
。 相反地,您會提供處理常式函式,並將該處理常式的訊息對應專案新增至擁有者視窗類別的訊息對應。
ClassWizard 可透過 ClassWizard 屬性工作表建立ON_NOTIFY訊息對應專案,並提供基本架構處理常式函式。 如需使用 ClassWizard 來簡化此作業的詳細資訊,請參閱 將訊息對應至函式 。
ON_NOTIFY訊息對應宏具有下列語法:
ON_NOTIFY(wNotifyCode, id, memberFxn)
其中的參數:
wNotifyCode
要處理之通知訊息的程式碼,例如LVN_KEYDOWN。
id
傳送通知之控制項的子識別碼。
memberFxn
傳送此通知時要呼叫的成員函式。
您的成員函式必須以下列原型宣告:
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
其中的參數:
pNotifyStruct
通知結構的指標,如上一節所述。
result
傳回之前所設定結果碼的指標。
範例
若要指定成員函 OnKeydownList1
式要處理其識別碼為 IDC_LIST1
的 CListCtrl
LVN_KEYDOWN 訊息,您可以使用 ClassWizard 將下列內容新增至訊息對應:
ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)
在上述範例中,ClassWizard 所提供的函式為:
void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
// TODO: Add your control notification handler
// code here
*pResult = 0;
}
請注意,ClassWizard 會自動提供適當類型的指標。 您可以透過 pNMHDR 或 pLVKeyDow 存取通知結構。
ON_NOTIFY_RANGE
如果您需要處理一組控制項的相同WM_NOTIFY訊息,您可以使用ON_NOTIFY_RANGE,而不是ON_NOTIFY。 例如,您可能有一組按鈕,您想要針對特定通知訊息執行相同的動作。
當您使用ON_NOTIFY_RANGE時,您可以指定連續的子識別碼範圍,藉由指定範圍的開頭和結束子識別碼來處理通知訊息。
ClassWizard 不會處理ON_NOTIFY_RANGE;若要使用它,您必須自行編輯訊息對應。
ON_NOTIFY_RANGE的訊息對應專案和函式原型如下所示:
ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)
其中的參數:
wNotifyCode
要處理之通知訊息的程式碼,例如LVN_KEYDOWN。
id
連續識別碼範圍中的第一個識別碼。
idLast
連續識別碼範圍中的最後一個識別碼。
memberFxn
傳送此通知時要呼叫的成員函式。
您的成員函式必須以下列原型宣告:
afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
其中的參數:
id
傳送通知之控制項的子識別碼。
pNotifyStruct
通知結構的指標,如上所述。
result
傳回之前所設定結果碼的指標。
ON_NOTIFY_EX,ON_NOTIFY_EX_RANGE
如果您想要通知路由中的多個物件來處理訊息,您可以使用ON_NOTIFY_EX(或ON_NOTIFY_EX_RANGE),而不是ON_NOTIFY(或ON_NOTIFY_RANGE)。 EX 版本與一般版本的唯 一 差異在於,針對 EX 版本呼叫 的成員函式會傳回 BOOL ,指出訊息處理是否應該繼續。 從此函式傳 回 FALSE 可讓您在多個 物件中處理相同的訊息。
ClassWizard 不會處理ON_NOTIFY_EX或ON_NOTIFY_EX_RANGE;如果您想要使用其中一個,您必須自行編輯訊息對應。
ON_NOTIFY_EX和ON_NOTIFY_EX_RANGE的訊息對應專案和函式原型如下所示。 參數的意義與非 EX 版本相同。
ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)
上述兩者的原型都相同:
afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
在這兩種情況下, id 會保存傳送通知之控制項的子識別碼。
如果已完全處理通知訊息, 您的函式必須傳回 TRUE ;如果命令路由中的其他物件應該有機會處理訊息,則此函式必須傳回 FALSE 。