共用方式為


TN061:ON_NOTIFY和WM_NOTIFY訊息

備註

自第一次包含在在線文件中以來,尚未更新下列技術附注。 因此,某些程式和主題可能已過期或不正確。 如需最新信息,建議您搜尋在線檔索引中感興趣的主題。

此技術附注提供新WM_NOTIFY訊息的背景資訊,並說明在 MFC 應用程式中處理WM_NOTIFY訊息的建議(和最常見)方式。

Windows 3.x 中的通知訊息

在 Windows 3.x 中,控件會藉由傳送訊息給父系,通知發生事件,例如滑鼠按鍵、內容變更和選擇,以及控制背景繪製。 簡單通知會以特殊的WM_COMMAND訊息傳送,其中包含通知碼(例如BN_CLICKED),以及封裝在 wParam 中的控件識別碼,以及控件在 lParam 中的句柄。 請注意,由於 wParamlParam 已滿,因此無法傳遞任何其他數據, 這些訊息只能是簡單的通知。 例如,在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 為 CListCtrlIDC_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 會自動提供適當類型的指標。 您可以透過 pNMHDRpLVKeyDow 存取通知結構。

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

另請參閱

依編號的技術注意事項
依類別排序的技術注意事項