对于一条MFC消息响应函数,一般会有三处相关信息。


1. 消息响应函数声明


project1Dlg.h    (如何多doc文档则是xxxView.h)


class Cproject1Dlg : public CDialog
{
// 构造
public:
 Cproject1Dlg(CWnd* pParent = NULL); // 标准构造函数

// 对话框数据
 enum { IDD = IDD_PROJECT1_DIALOG };

 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持


// 实现
protected:
 HICON m_hIcon;

 // 生成的消息映射函数
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 DECLARE_MESSAGE_MAP()
public:
 afx_msg void OnBnClickedOk();  //函数声明,声明了是消息响应函数
};

 

 


2.   消息响应函数定义

 project1Dlg.cpp

 

void Cproject1Dlg::OnBnClickedOk()
{
 // TODO: 在此添加控件通知处理程序代码
 OnOK();
}


3.  书写消息映射宏,表示遇到该宏对应消息时,将消息与消息响应函数关联,调用消息响应函数


BEGIN_MESSAGE_MAP(Cproject1Dlg, CDialog)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 //}}AFX_MSG_MAP
 ON_BN_CLICKED(IDOK, OnBnClickedOk)
END_MESSAGE_MAP()

 

 
ON_BN_CLICKED(IDOK, OnBnClickedOk)与OnBnClickedOk()  通过参数对应的关系显得很清晰。而原有的VC机制常用ON_WM_LBUTTONDOWN与响应函数OnLButtonDown()对应,这对书写有严格要求,不能错,因为VC中存在了一个消息映射表这样的东西,对每个消息宏(如ON_WM_LBUTTONDOWN)都预定义了消息映射函数(如OnLButtonDown())这样的虚函数,使用时定义一下就可以,但必须按映射表的原函数书写才能关联消息宏。

 如何消息映射表中没有该消息及响应函数,想自定义一个。

转一个MFC自定义消息的实现


1).在相关类的头文件顶部添加如下所示的字串(以CMyDlg类为例):
在CMyDlg.h中添加#define WM_MY_MESSAGE (WM_USER+100)  注意:在源文件(。cpp)也可以的。
                                                               1                    2
其中1位置处的消息名可以自定,位置2处是确保消息在程序中唯一性,所以用(WM_USER+数值)的形式来表示,数值不可为负.

2).在消息定义完成后,需要转到相应类的源程序文件CMyDlg.cpp中,在如下所示的固定结构间添加消息与函数的映射.
BEGIN_MESSAGE_MAP(CTestdisockDlg, CDialog)
//{{AFX_MSG_MAP(CTestdisockDlg)

//}}AFX_MSG_MAP
END_MESSAGE_MAP()

例如要添加上面已经定义好的消息,添加后的结构如下:
BEGIN_MESSAGE_MAP(CTestdisockDlg, CDialog)
//{{AFX_MSG_MAP(CTestdisockDlg)
ON_MESSAGE(WM_NOTIFY_MESSAGE, OnMyMessage) //3
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
其中3所示的行即是添加的内容.要注意自定义消息是以ON_MESSAGE()的形式映射,第一个参数是上面已经定义好的消息名,第二个参数是该消息的映射函数,消息是函数的触发条件.无消息到达时该函数永远不被执行.

3).上面的完成后,需要转到CMyDlg.h文件中,也就是定义类的文件中,在如下的结构中申明刚才映射好的函数.
//{{AFX_MSG(CTestdisockDlg)
virtual BOOL OnInitDialog();

//}}AFX_MSG
DECLARE_MESSAGE_MAP()   //找位置的时候,以该行出现的地方为准.
添加函数后的结构如下,与普通的申明稍有区别.
//{{AFX_MSG(CTestdisockDlg)
virtual BOOL OnInitDialog();
afx_msg OnMyMessage();    //4
//}}AFX_MSG
DECLARE_MESSAGE_MAP()   //找位置的时候,以该行出现的地方为准,添加函数后的结构如下,与普通的申明稍有区别.

位置4对应的行是加上的函数申明,如果有参数就写带参的形式,其中afx_msg 头是所有与消息有关的函数必须加的标识.
最后一步就是到源文件CMyDlg.cpp中写函数的实现部分,也就是具体的编程.
消息的触发是靠SendMessage()或PostMessage()函数完成的,它们的第一个参数就是指定把消息发往那个窗口,发送成功后,映射函数就会被调用执行。

 小白特别提示: 在很多动态菜单自定义函数问题上,ON_MESSAGE会无效,推荐用ON_COMMAND

ON_COMMAND 对应的都是WM_COMMAND消息,是用户自定义消息的较好发布者

两者区别非常理论

窗口消息(Window Message)一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗等。通常,消息是从系统发送到窗口,或从窗口发送到窗口。
若需要窗口消息的完全的列表,请参考M F C文档。


命令消息
命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生,并被发送到能处理该请求的类对象(如,装载文件、编辑文本和保存选项等)。


控件通知
通常,控件通知在某些重要事件发生时,由控件窗口发送到父窗口,如打开一个组合框。

控件通知为父窗口进一步控制子窗口提供了机会。例如,打开一个组合框时,父窗口可以用组合框初建时得不到的消息填充它。

ON_COMMAND 和ON_MESSAGE都是将消息处理函数加入消息路由表中,但是ON_COMMAND对应的消息ID一直都是WM_COMMAND,而ON_MESSAGE的消息ID为ON_COMMAND的第一个参数