MFC_常见的消息,宏替换分析MFC消息映射

文章目录

  • 1. MFC常见的消息
  • 2. 分析MFC消息映射

1. MFC常见的消息

系统消息:

首先,MFC将Win32的回调函数封装起来,通过的映射的方式来让用户实现各种消息的响应。

在设计MFC消息响应时,首先要在窗口处理类中声明消息映射

DECLARE_MESSAGE_MAP();//声明消息映射
BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
//消息处理
END_MESSAGE_MAP()

响应按钮消息:

此外,还要特别注意,MFC中没有WM_COMMAND消息,如果要相应响应的按钮,直接写ON_BN_CLICKED(id(按钮ID), memberFxn),之后在窗口类中实现写按钮处理函数即可

按钮处理函数类型void name()

用户自定义消息:

自定义消息不可以与系统重复

WM_USER以上的消息都可以作为用户自定义消息值。

MFC中需要宏函数ON_MESSAGE来响应自定义消息

ON_MESSAGE(message(消息ID), memberFxn(自定义消息处理函数))

注意:自定义消息处理函数类型:

LRESULT name(WPARAM,LPARAM)

MFC没有解析,需要自己对WPARAM,LPARAM数据进行处理。

解析方式与Win32的解析方式类似.

注意:自定义消息类型要通过PostMessage/SendMessage函数发送

eg:
公共头文件stdafx.h

#pragma once
#include
#include"resource.h"

//用户自定义消息
#define WM_MYMSG WM_USER+1

窗口类

#pragma once
#include"stdafx.h"

//对话框类,一般一个类关联一个窗口
class CMainDialog :public CDialog {
private:
	HICON m_hicon;
	HICON n_hicon;
public:
	CMainDialog();
	//初始化函数,名字不能改动
	BOOL OnInitDialog();

	//声明消息映射
	DECLARE_MESSAGE_MAP();

	//消息处理函数 WM_CREATE消息处理函数
	int OnCreate(LPCREATESTRUCT lpCs);

	//关闭消息 WM_CLOSE消息处理函数
	void OnClose();
	//WM_DESTORY
	void OnDestory();
	//WM_PAINT
	void OnPaint();
	//WM_TIMER消息
	void OnTimer(UINT_PTR id);
	//WM_SIZE消息
	void OnSize(UINT nType, int cx, int cy);
	//鼠标移动
	void OnLButtonDown(UINT nflag,CPoint point);
	void OnMouseMove(UINT nflag, CPoint point);
	//文件拖拽消息
	void OnDropFiles(HDROP path);

	//按钮响应函数
	void OnOk();
	//自定义按钮响应函数
	void OnTest();
	//自定义消息
	LRESULT OnMyMsg(WPARAM wparam, LPARAM lparam);
};

窗口类函数实现

#include"MainDialog.h"

#define TIME_ID 1
#define TIME_ICON 2

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
	ON_WM_CREATE()//窗口创建消息
	ON_WM_CLOSE()//窗口关闭消息
	ON_WM_DESTROY()
	ON_WM_PAINT()
	ON_WM_TIMER()//定时器消息
	ON_WM_SIZE()//窗口大小变化函数
	//鼠标消息
	ON_WM_LBUTTONDOWN()//左键按下
	ON_WM_MOUSEMOVE()//鼠标移动
	//文件拖拽消息
	ON_WM_DROPFILES()
	//按钮消息
	ON_BN_CLICKED(IDOK, &CMainDialog::OnOK)
	//自定义按钮消息
	ON_BN_CLICKED(IDC_BUT_TEST, &CMainDialog::OnTest)
	//自定义消息
	ON_MESSAGE(WM_MYMSG, &CMainDialog::OnMyMsg)
END_MESSAGE_MAP()

//On_WM_CLOSE响应函数
void CMainDialog::OnClose() {
	int ret = MessageBox(L"确认关闭吗?", L"提示", MB_YESNO);
	if (ret == IDYES) {
		CDialog::OnClose();//发出WM_DESTORY消息
	}
	else {
		ShowWindow(SW_MINIMIZE);
	}
}

//WM_DESTORY,窗口资源已经销毁
void CMainDialog::OnDestory()
{
	CDialog::OnDestroy();
}

//WM_PAINT函数
void CMainDialog::OnPaint()
{
	CPaintDC dc(this);
	dc.Rectangle(0, 0, 200, 200);
	CDialog::OnPaint();
}

//WM_TIMER
void CMainDialog::OnTimer(UINT_PTR id)
{
	static bool flag = false;
	switch (id)
	{
		case TIME_ID: {
			CTime time = CTime::GetCurrentTime();
			CString msg = time.Format(L"当前时间:%Y-%m-%d %H:%M:%S");
			SetWindowText(msg);
			break;
		}
		case TIME_ICON: {//设置图标
			if (flag == false) {
				SetIcon(m_hicon, TRUE);
				SetIcon(m_hicon, FALSE);
				flag = true;
			}
			else {
				SetIcon(n_hicon, TRUE);
				SetIcon(n_hicon, FALSE);
				flag = false;
			}
			break;
		}
	}
}

//ON_WM_SIZE消息
void CMainDialog::OnSize(UINT nType, int cx, int cy)
{
	KillTimer(TIME_ID);
	CString msg;
	msg.Format(L"长:%d 宽:%d", cx, cy);
	SetWindowText(msg);
}

void CMainDialog::OnLButtonDown(UINT nflag, CPoint point)
{
	CString Str;
	if (nflag & MK_CONTROL) {
		Str += L"按下Ctrl键 ";
	}
	else if (nflag & MK_LBUTTON) {
		Str += L"按下鼠标左键";
	}
	else if (nflag & MK_MBUTTON) {
		Str += L"按下鼠标中键";
	}
	//……
	Str.Format(L"%s 坐标(x=%d,y=%d)", Str.GetBuffer(), point.x, point.y);
	SetWindowText(Str);
	CDialog::OnLButtonDown(nflag, point);
}

void CMainDialog::OnMouseMove(UINT nflag, CPoint point)
{
	CDialog::OnMouseMove(nflag, point);
}

void CMainDialog::OnDropFiles(HDROP dropInfo)
{
	CDialog::OnDropFiles(dropInfo);
}

void CMainDialog::OnOk()
{
	CDialog::OnOK();//调用EndDialog(hwnd,IDOK)
}

void CMainDialog::OnTest()
{
	MessageBox(L"发送自定义消息", L"提示", MB_OK);
	SendMessage(WM_MYMSG, 10, 20);
}

LRESULT CMainDialog::OnMyMsg(WPARAM wparam, LPARAM lparam)
{
	//自己对WPARAM wparam, LPARAM lparam进行解析
	long ret = wparam + lparam;
	CString debug;
	debug.Format(L"debug:%d", ret);
	OutputDebugString(debug);
	//关闭闪烁图标定时器
	KillTimer(TIME_ICON);
	return ret;
}



//ON_WM_CREATE()响应函数,最先发出
int CMainDialog::OnCreate(LPCREATESTRUCT lpCs) {
	//MessageBox(L"WM_CREATE消息已经响应");
	CString str(L"Hello MFC");
	SetWindowText(str);

	int len = str.GetLength();

	//获取鼠标坐标
	CPoint point;
	GetCursorPos(&point);

	//CString msg;
	//msg.Format(L"当前鼠标坐标(X=%d,Y=%d)", point.x, point.y);
	//
	//SetWindowText(msg);
	//设置图标
	SetIcon(m_hicon, TRUE);//大图标
	SetIcon(m_hicon, FALSE);//小图标

	//大小类
	CSize size(800, 600);

	//CRect代表矩形类
	CRect rect(10, 20, 200, 100);
	CPoint top_left = rect.TopLeft();
	CPoint end_right = rect.BottomRight();
	CPoint mid_point = rect.CenterPoint();
	//判断点是否在矩形中
	rect.PtInRect(point);

	return CDialog::OnCreate(lpCs);
}

CMainDialog::CMainDialog()
	:CDialog(IDD_MAIN_DIALOG) {
	//图标资源句柄
	m_hicon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MAIN_ICON));
	n_hicon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NEXT_ICON));
	//m_hicon = TheApp.LoadIcon(IDI_MAIN_ICON);
}

//初始化函数,名字不能改动 响应WM_INITDIALOG消息
BOOL CMainDialog::OnInitDialog() {
	//启动定时器
	SetTimer(TIME_ID, 1000, NULL);

	//图标定时器
	SetTimer(TIME_ICON, 500, NULL);//2s改一次图标
	return TRUE;
}

主函数

#include"stdafx.h"
#include"FirstMFC.h"
#include"MainDialog.h"

#pragma once
class MainApp :public CWinApp {
public:
	//初始化
	BOOL InitInstance();

	//资源释放
	BOOL ExitInstance();
};

MainApp TheApp;

//启动管理
BOOL MainApp::InitInstance() {
	/*MessageBox(NULL, L"First MFC", L"提示", MB_OK);*/

	CMainDialog dig;
	dig.DoModal();
	return TRUE;//初始化成功
}

//资源释放
BOOL MainApp::ExitInstance() {
	return FALSE;
}

2. 分析MFC消息映射

在MFC中处理消息时要在窗口类中使用消息映射

//声明消息映射
DECLARE_MESSAGE_MAP();

BEGIN_MESSAGE_MAP(CDilaog 派生类, CDialog) 
//……
END_MESSAGE_MAP()

声明消息映射看定义为:
MFC_常见的消息,宏替换分析MFC消息映射_第1张图片

声明DECLARE_MESSAGE_MAP()相当于声明了两个受保护的成员函数


BEGIN_MESSAGE_MAP(CDilaog 派生类, CDialog)可以看作:
MFC_常见的消息,宏替换分析MFC消息映射_第2张图片
theClass:就是用户自定义的CDialog的派生类
baseClass:就是基础类CDialog基类
PTM_WARNING_DISABLE:编译器优化。

_messageEntries[]这一部分没有写完,需要配合END_MESSAGE_MAP()这个宏,拼起来才是完成的。


END_MESSAGE_MAP()可以看作为:
MFC_常见的消息,宏替换分析MFC消息映射_第3张图片
将其拼接,去掉编译器优化代码,将theClass和baseClass替换,最终得到的代码如下:

const AFX_MSGMAP* CMainDialog::GetMessageMap() const 
{
	return GetThisMessageMap();
} 

const AFX_MSGMAP* PASCAL CMainDialog::GetThisMessageMap()
{ 
	typedef CMainDialog ThisClass;
	typedef CDialog TheBaseClass;
	static const AFX_MSGMAP_ENTRY _messageEntries[] =  
	{
		ON_WM_CREATE()//窗口创建消息
		ON_WM_CLOSE()//窗口关闭消息
		ON_WM_DESTROY()
		ON_WM_PAINT()
		ON_WM_TIMER()//定时器消息
		ON_WM_SIZE()//窗口大小变化函数
//-----END_MESSAGE_MAP
		{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } //这个数组元素一定在这个数组的末尾
	}; 

	static const AFX_MSGMAP messageMap = 
	{ 
		&CDialog::GetThisMessageMap, &_messageEntries[0]
	};
	return &messageMap; 
}

BEGIN_MESSAGE_MAP+END_MESSAGE_MAP拼起来就是DECLARE_MESSAGE_MAP()在派生窗口类声明的两个函数的实现。

其中AFX_MSGMAP_ENTRY是一个结构体,成员变量如下:
MFC_常见的消息,宏替换分析MFC消息映射_第4张图片
而我们声明的类似于

ON_WM_CREATE()//窗口创建消息
ON_WM_CLOSE()//窗口关闭消息
ON_WM_DESTROY()
ON_WM_PAINT()
ON_WM_TIMER()//定时器消息
ON_WM_SIZE()//窗口大小变化函数

这些消息也属于宏,究其本质如下图:
在这里插入图片描述
添加消息宏就相当于是向_messageEntries[]这个数组里面添加元素。

以WM_DESTROY为例添加的元素为:

{ WM_DESTROY, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(static_cast<void (AFX_MSG_CALL CWnd::*)(void)> (&ThisClass::OnDestroy)) },

这些值就相当于在给AFX_MSGMAP_ENTRY这个结构体的成员变量赋值,最后带逗号是因为数组之间的元素是以,分割的。

将上面的宏替换成解析后的代码也是可以正常运行的。

注意:

  1. ON_BN_CLICKED这个按钮消息需要经过两步才会给AFX_MSGMAP_ENTRY结构体类型赋值,这里不在赘述
  2. {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 这个数组元素在END_MESSAGE_MAP()宏中,这个元素一定在数组的最后一个位置
    这个标记这个数组元素的结尾,遍历到这里代表映射数组已经遍历完毕了。

你可能感兴趣的:(Windows_MFC,mfc,c++,windows)