消息映射機制
- Window消息分類
- 消息映射機制的使用
- 代碼示例
MFC框架利用消息映射機制把消息、命令與它們的處理函數映射起來。具體實現方法是在每個能接收和處理消息的類中,定義一個消息和消息函數指針對照表,即消息映射表。
在不重寫WindowProc虛函數的大前提下,仍然可以處理消息。
Window消息分類
- 標準Windows消息:除WM_COMMAND外以WM_開頭的消息都是標準消息。
- 命令消息:消息名為WM_COMMAND,消息中附帶了標識符ID來區分來自哪個菜單、工具欄按鈕或加速鍵的消息。
- 通知消息:通知消息一般由列表框等子窗口發送給父窗口,消息名也是WM_COMMAND,其中附帶了控件通知碼來區分控件。
- 用戶自定義消息:用戶定義一個宏作為消息,值大于WM_USER。
CWnd的派生類可以接收者四種消息,命令消息還可以由文檔類接收。
命令消息的處理順序:框架類(CFrameWnd派生類)優先于應用程序類(CWinApp派生類)。視圖類(CView派生類)優先于框架類(CFrameWnd派生類)。
消息映射可以通過VS2022的菜單項自動生成
項目-》類向導 選擇你需要再哪個類中添加對應的消息。
如下圖:
消息映射機制的使用
- 類內必須添加聲明宏
DECLARE_MESSAGE_MAP()
- 類外必須添加實現宏
BEGIN_MESSAGE_MAP(theClass,baseClass) END_MESSAGE_MAP()
當一個類具備上述兩個條件,這個類就可以按照消息映射機制來處理消息。
代碼示例
#include <afxwin.h>
#include "resource.h"//自定義消息
#define WM_MYMESSAGE WM_USER+1001//1.定義自己的框架類CMyFrameWnd,派生自CFrameWnd類
class CMyFrameWnd :public CFrameWnd {DECLARE_MESSAGE_MAP()public:afx_msg int OnCreate(LPCREATESTRUCT param);afx_msg void OnPaint(void);afx_msg void OnMouseMove(UINT nKey, CPoint pt);afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);afx_msg void OnOpen();afx_msg void OnInitMenuPopup(CMenu* pPopup,UINT nPos, BOOL i);afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);int m_x;int m_y;CMenu menu;};BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)//使用標準消息實現WM_CREATE (窗口創建)消息的處理ON_WM_CREATE()//使用標準消息實現WM_PAINT(繪圖)消息的處理ON_WM_PAINT()//使用標準消息實現鼠標移動消息ON_WM_MOUSEMOVE()//自定義消息ON_MESSAGE(WM_MYMESSAGE,OnMyMessage)//命令消息ON_COMMAND(ID_OPEN, &CMyFrameWnd::OnOpen)//標準消息ON_WM_INITMENUPOPUP()//標準消息ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()//ON_WM_CREATE消息調用的函數
int CMyFrameWnd::OnCreate(LPCREATESTRUCT param) {//加載菜單方式二menu.LoadMenu(IDR_MENU1);this->SetMenu(&menu);AfxMessageBox("ON_WM_CREATE");//發送自己定義的消息::PostMessage(this->m_hWnd, WM_MYMESSAGE, 1, 2);return CFrameWnd::OnCreate(param);
}//ON_WM_PAINT消息調用的函數
void CMyFrameWnd::OnPaint(void) {PAINTSTRUCT ps = { 0 };HDC hdc = ::BeginPaint(this->m_hWnd, &ps);::TextOutA(hdc, m_x, m_y, "hello", 5);::EndPaint(m_hWnd, &ps);
}//OnMouseMove消息調用的函數
void CMyFrameWnd::OnMouseMove(UINT nKey, CPoint pt) {m_x = pt.x;m_y = pt.y;//hello 字符串跟著鼠標移動::InvalidateRect(this->m_hWnd, NULL, TRUE);}
//自定義消息
LRESULT CMyFrameWnd::OnMyMessage(WPARAM wParam, LPARAM lParam) {CString str;str.Format("wParam=%d, lParam=%d", wParam, lParam);AfxMessageBox(str);return 0;
}//命令消息 點擊打開
void CMyFrameWnd::OnOpen()
{AfxMessageBox("ON_COMMAND");
}//設置菜單狀態
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{//ID為ID_OPEN的菜單項前面打對號pPopup->CheckMenuItem(ID_OPEN,MF_CHECKED);
}//鼠標右鍵
void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint point)
{//HMENU hPopup = ::GetSubMenu(menu.m_hMenu,0);//展示菜單//::TrackPopupMenu(hPopup,TPM_LEFTALIGN|TPM_TOPALIGN,point.x,point.y,0,this->m_hWnd,NULL);//上下兩種方式均可CMenu* pPopup = menu.GetSubMenu(0);//展示菜單pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, point.x, point.y,this);
}//定義自己應用程序類CMyWinApp,派生自CWinApp類,
//并定義構造以及重寫InitInstance虛函數,在函數中創建并顯示窗口
class CMyWinApp :public CWinApp {public :CMyWinApp() {}virtual BOOL InitInstance() {CMyFrameWnd* pFrame = new CMyFrameWnd;//最后一個參數 加載菜單方式一(常用)//pFrame->Create(NULL,"MFCBase",WS_OVERLAPPEDWINDOW,CFrameWnd::rectDefault,NULL,(CHAR*)IDR_MENU1);pFrame->Create(NULL, "MFCBase");m_pMainWnd = pFrame;pFrame->ShowWindow(SW_SHOW);pFrame->UpdateWindow();return TRUE;}
};//3.定義CMyWinApp類的對象(程序的爆破點)
CMyWinApp theApp;