一、消息映射
1、创建工程
2、编写代码
#include <afxwin.h>
class CMyFrameWnd : public CFrameWnd
{
//DECLARE_MESSAGE_MAP();
protected:
static const AFX_MSGMAP* PASCAL GetThisMessageMap();
virtual const AFX_MSGMAP* GetMessageMap() const;
public:
LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
};
//BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
// ON_MESSAGE(WM_CREATE, OnCreate)
//END_MESSAGE_MAP()
PTM_WARNING_DISABLE
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{
return GetThisMessageMap();
}
const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
{
static const AFX_MSGMAP_ENTRY _messageEntries[] =
{
{ WM_CREATE, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >(OnCreate)) },
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}
};
static const AFX_MSGMAP messageMap =
{
&CFrameWnd::GetThisMessageMap, &_messageEntries[0]
};
return &messageMap;
}
PTM_WARNING_RESTORE
LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox("WM_CREATE 消息处理");
return 0;
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCCreate");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
3、代码解析(宏展开内容)
(1)虚函数调用静态函数
virtual const AFX_MSGMAP* GetMessageMap() const;
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{
//获取本类的messagemap静态遍历地址
return GetThisMessageMap();
}
(2)静态函数创建静态结构体(AFX_MSGMAP_ENTRY)数组,结构体最后一个元素为消息处理函数
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // 消息ID
UINT nCode; // 通知码
UINT nID; // 命令ID
UINT nLastID; // 最后一个命令ID
UINT_PTR nSig; // 处理消息的函数类型
AFX_PMSG pfn; // 处理函数地址(名称)
};
static const AFX_MSGMAP_ENTRY _messageEntries[] =
{
{ WM_CREATE, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >(OnCreate)) },
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}
};
(3)静态函数创建静态结构体(AFX_MSGMAP),第一个元素为类父类的静态结构体(AFX_MSGMAP)地址,第二个元素为上一步创建的静态结构体(AFX_MSGMAP_ENTRY)数组地址
static const AFX_MSGMAP messageMap =
{
&CFrameWnd::GetThisMessageMap,
&_messageEntries[0]
};
(4)由静态结构体(AFX_MSGMAP)组成的列表(链表头:当前类的结构体(AFX_MSGMAP_ENTRY);下一个元素:父类的结构体(AFX_MSGMAP_ENTRY))
4、消息处理原理
(1)由当前类(申明消息处理的类)获取列表头,遍历获取消息处理函数,然后调用消息处理函数
(2)消息追踪
//以WM_CREATE消息为例,捎带想着点WM_PAINT,WM_COMMAND(到了CWnd::OnWndMsg函数路线不一样)
AfxWndProc(...)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
//获取和hWnd绑定在一起的框架类对象地址(pFrame===pWnd)
AfxCallWndProc(pWnd...)//参数pWnd===pFrame
{
pWnd->WindowProc(...)//函数内部this为pFrame===pWnd *************
{
OnWndMsg(...)//函数内部this为pFrame===pWnd
{
const AFX_MSGMAP* pMessageMap = GetMessageMap();
//获取本类宏站开的静态变量的地址(链表头结点)
const AFX_MSGMAP_ENTRY* lpEntry;
for (; pMessageMap->pfnGetBaseMap != NULL;//此for就是在遍历链表
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,message, 0, 0));
//如果找到返回找到的数组元素的地址,如果没找到返回NULL
if(lpEntry != NULL )
{
goto LDispatch;
}
}
LDispatch:
lpEntry->pfn; //CMyFrameWnd::OnCreate
调用CMyFrameWnd::OnCreate函数完成消息的处理
}
}
}
}
二、消息的分类
1、分类
(1)标准Windows消息
ON_WM_XXX
ON_WM_CREATE //创建消息
ON_WM_APINT //绘图消息
(2)自定义消息
ON_MESSAGE
(3)命令消息
ON_COMMAND
2、创建项目(MFCCmd)
3、编写程序
#include <afxwin.h>
//自定义消息
#define WM_MYMESSAGE WM_USER+1001
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnPaint();
afx_msg void OnMouseMove(UINT nKey,CPoint pt);
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
private:
CPoint m_pt;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE() //替换ON_WM_CREATE
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
AfxMessageBox("WM_CREATE 消息处理");
::PostMessage(m_hWnd, WM_MYMESSAGE, 1, 2); //发送消息
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps={0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOut(hdc, m_pt.x, m_pt.y, "WM_PAINT 绘图消息", strlen("WM_PAINT 绘图消息"));
::EndPaint(m_hWnd, &ps);
}
//鼠标移动消息
void CMyFrameWnd::OnMouseMove(UINT nKey,CPoint pt)
{
m_pt.x = pt.x;
m_pt.y = pt.y;
//调用画图(画矩形),触发绘图消息
::InvalidateRect(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;
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCCreate");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
三、MFC菜单(命令消息)
1、菜单相关
Win32 -》菜单句柄HMENU
MFC -》CMENU类对象,该类的m_hMenu保存了菜单句柄(HMENU)
2、菜单使用步骤
(1)添加菜单资源
(2)将菜单设置到窗口
方式1:利用pFrame调用Create函数时,传参绑定
方式2:在处理框架窗口的WM_CREATE消息时
CMenu menu;
menu.LoadMenu(...);
3、创建项目(MFCMenu)
(1)创建项目
(2)添加资源文件(.rc),添加菜单资源
(3)编写代码
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
private:
CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
m_menu.LoadMenu(IDR_MENU1); //绑定菜单句柄
SetMenu(&m_menu);
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
//pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
(4)命令消息(菜单消息)
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
private:
CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("框架类处理了-新建菜单项");
}
class CMyWinApp : public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("应用类处理了-新建菜单项");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
//pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
(5)命令消息处理顺序
框架类 -> 应用类程序类
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
private:
CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("框架类处理了-新建菜单项");
}
class CMyWinApp : public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("应用类处理了-新建菜单项");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
//pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
4、菜单项状态(勾选)
(1)消息与函数
Win32:
WM_INITMENUPOPUP
::CheckMenuItem / ::EnableMenuItem
MFC:
ON_WM_INITMENUPOPUP
CMenu::CheckMenuItem / CMenu::EnableMenuItem
(2)程序
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
afx_msg void OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i);
private:
CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_COMMAND(ID_NEW, OnNew)
ON_WM_INITMENUPOPUP()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("框架类处理了-新建菜单项");
}
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{
//::CheckMenuItem(pPopup->m_hMenu, ID_NEW, MF_CHECKED);
pPopup->CheckMenuItem(ID_NEW, MF_CHECKED);
}
class CMyWinApp : public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("应用类处理了-新建菜单项");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
//pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;
5、右键菜单项(在界面右键,将显示菜单)
(1)消息与函数
Win32:
WM_CONTEXTMENU
::TrackPopupMenu
MFC:
ON_WM_CONTEXTMENU
CMenu::TrackPopupMenu
(2)程序
#include <afxwin.h>
#include "resource.h"
class CMyFrameWnd : public CFrameWnd
{
DECLARE_MESSAGE_MAP();
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
afx_msg void OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint pt);
private:
CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_COMMAND(ID_NEW, OnNew)
ON_WM_INITMENUPOPUP()
ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("框架类处理了-新建菜单项");
}
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{
//::CheckMenuItem(pPopup->m_hMenu, ID_NEW, MF_CHECKED);
pPopup->CheckMenuItem(ID_NEW, MF_CHECKED);
}
void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint pt)
{
/*
HMENU pPopup = ::GetSubMenu(m_menu.m_hMenu, 0); //获取菜单项句柄
::TrackPopupMenu(pPopup, TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, 0, m_hWnd, NULL);
*/
CMenu* pPopup = m_menu.GetSubMenu(0);
pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, this);
}
class CMyWinApp : public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("应用类处理了-新建菜单项");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
//pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
//应程序入口
CMyWinApp theApp;