系统消息:
首先,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;
}
在MFC中处理消息时要在窗口类中使用消息映射
//声明消息映射
DECLARE_MESSAGE_MAP();
BEGIN_MESSAGE_MAP(CDilaog 派生类, CDialog)
//……
END_MESSAGE_MAP()
声明DECLARE_MESSAGE_MAP()
相当于声明了两个受保护的成员函数
BEGIN_MESSAGE_MAP(CDilaog 派生类, CDialog)可以看作:
theClass:就是用户自定义的CDialog的派生类
baseClass:就是基础类CDialog基类
PTM_WARNING_DISABLE:编译器优化。
_messageEntries[]这一部分没有写完,需要配合END_MESSAGE_MAP()这个宏,拼起来才是完成的。
END_MESSAGE_MAP()可以看作为:
将其拼接,去掉编译器优化代码,将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是一个结构体,成员变量如下:
而我们声明的类似于
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这个结构体的成员变量赋值,最后带逗号是因为数组之间的元素是以,分割的。
将上面的宏替换成解析后的代码也是可以正常运行的。
注意: