備註
自第一次包含在在線文件中以來,尚未更新下列技術附注。 因此,某些程式和主題可能已過期或不正確。 如需最新信息,建議您搜尋在線檔索引中感興趣的主題。
此技術附注提供新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 中支持的控件。 這些控件經常需要傳送其他數據及其通知訊息。 與其為每個需要額外數據的新通知新增一個新的 WM_* 訊息,Win32 API 的設計者選擇只新增一則訊息,即 WM_NOTIFY,這訊息可以以標準化的方式傳遞任意數量的額外數據。
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。
識別碼
傳送通知之控件的子標識碼。
memberFxn
傳送此通知時要呼叫的成員函式。
您的成員函式必須以下列原型宣告:
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
其中參數為:
pNotifyStruct
指向通知結構的指標,如上一節所述。
結果
返回前您將設置的結果碼指標。
範例
若要指定成員函式 OnKeydownList1 處理來自 ID 為 CListCtrl 的 IDC_LIST1 的 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。
識別碼
連續標識碼範圍中的第一個標識碼。
idLast
連續標識碼範圍中的最後一個標識碼。
memberFxn
傳送此通知時要呼叫的成員函式。
您的成員函式必須以下列原型宣告:
afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
其中參數為:
識別碼
傳送通知之控件的子標識碼。
pNotifyStruct
通知結構的指標,如上所述。
結果
返回前您將設置的結果碼指標。
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 。