首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

深入解析 WM_NOTIFY 消息機制與 MFC 實作技巧

     編輯:VC 教學

前言:控制項通知訊息的分類與演進

在 Visual C++ 開發中,視窗消息主要分為三大類:視窗消息、命令消息與控制項通知消息。本文著重探討最後一類——控制項通知消息。這類消息的核心在於:當視窗內的子控制項發生特定事件(如點擊、選取文字、捲動等)時,需通知父視窗進行相應處理。它適用於標準控制項(按鈕、列表方塊、編輯框)及 Windows 公用控制項(樹狀檢視、列表檢視等)。

雖然控制項通知消息與命令消息同樣從子視窗傳送至父視窗,但其目的不同:命令消息處理使用者指令,而控制項通知旨在讓父視窗能動態調整控制項行為(如載入資料、自訂繪製)。早期 Windows 3.x 僅透過 WM_COMMAND 傳遞簡單通知,但 wParam 與 lParam 已被佔用,無法攜帶額外資訊(如滑鼠座標)。為突破限制,Win32 引入 NMHDR 結構與 WM_NOTIFY 消息,實現靈活、擴充的通知機制。

三種控制項通知格式詳解

第一種格式:WM_XXXX 系列

屬於視窗消息子集,主要包含三類:

  • 建立/銷毀/滑鼠點擊通知: WM_PARENTNOTIFY
  • 自訂繪製相關: WM_CTLCOLOR、WM_DRAWITEM、WM_MEASUREITEM、WM_DELETEITEM、WM_CHARTOITEM、WM_VKTOITEM、WM_COMPAREITEM 等
  • 捲動通知: WM_VSCROLL、WM_HSCROLL

第二種格式:WM_COMMAND

與命令消息共用 WM_COMMAND。判斷依據在 lParam:若為 NULL 則為命令消息,否則為控制項句柄(通知消息)。wParam 低字為控制項 ID,高字為通知代碼。

第三種格式:WM_NOTIFY(核心重點)

最靈活、功能最強的格式。wParam 為控制項 ID,lParam 指向 NMHDR 結構:

typedef struct tagNMHDR {
    HWND hwndFrom;  // 發送通知的控制項句柄
    UINT idFrom;    // 控制項 ID
    UINT code;      // 通知代碼
} NMHDR;

NMHDR 設計巧妙:對於無附加資訊的通知,直接使用該結構;若有額外資料,則定義較大結構,首成員為 NMHDR。此特性使同一指標可通用於各類通知,並便於型別轉換。

NMHDR 結構的歷史背景與優勢

Windows 3.x 時代,通知僅能透過 WM_COMMAND 傳遞有限資訊。為解決空間不足,微軟曾採用「為每個消息定義專用結構」(如 DRAWITEMSTRUCT)的權宜之計,導致結構分散、維護困難。Win32 統一採用 NMHDR,將基本資訊標準化,並允許衍生結構擴充,極大提升了擴充性與一致性。

MFC 中的 ON_NOTIFY 與 ON_NOTIFY_RANGE 實作

ON_NOTIFY 宏語法與處理函數

ON_NOTIFY(wNotifyCode, id, memberFxn)
  • wNotifyCode:通知代碼(如 LVN_KEYDOWN)
  • id:控制項 ID
  • memberFxn:處理函數,原型為 afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result)

範例: 處理 IDC_LIST1 的 LVN_KEYDOWN

ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)

void CMyDialog::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult) {
    LV_KEYDOWN* pLVKey = (LV_KEYDOWN*)pNMHDR;
    // 可透過 pNMHDR 或 pLVKey 存取通知結構
    *pResult = 0;
}

類嚮導會自動提供對應型別的指標,方便開發者直接存取擴充欄位。

ON_NOTIFY_RANGE:批次處理同類控制項

需為一組連續 ID 的控制項處理相同通知時使用。VC6 類嚮導不支援,需手動加入訊息對應:

ON_NOTIFY_RANGE(wNotifyCode, idFirst, idLast, memberFxn)

處理函數原型:

afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

其中 id 為觸發通知的具體控制項 ID,其餘參數同 ON_NOTIFY。

總結

WM_NOTIFY 配合 NMHDR 結構,解決了早期通知機制資訊攜帶不足、結構碎片化的問題,成為 Win32 控制項通知的標準化基石。MFC 透過 ON_NOTIFY 與 ON_NOTIFY_RANGE 宏,提供了直觀、型別安全的訊息對應方式,配合類嚮導自動產生的型別轉換程式碼,大幅簡化了複雜控制項(如 List View、Tree View)的事件處理開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved