Customize your own MFC message
2007-12-05 17:24
381 查看
消息映射、循环机制是Windows程序运行的基本方式。VC++ MFC 中有许多现成的消息句柄,可当我们需要完成其它的任务,需要自定义消息,就遇到了一些困难。在MFC ClassWizard中不允许添加用户自定义消息,所以我们必须在程序中添加相应代码,以便可以象处理其它消息一样处理自定义消息。通常的做法是采取以下步骤:
Doc/View Application:
第一步:定义消息。
推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。
第三步:在类头文件的AFX_MSG块中说明消息处理函数:
第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
在引发或发出消息的地方只用写上:
::SendMessge(::AfxGetMainWnd()->m_hWnd,WM_MYMSG,0,0);
到此,自定义消息完毕,这是好多网上文章都写的东西。大家会发现上面代码是在CMainFrame类中实现的,但是如果要用自定义类,就没有那么简单了。显然把第四步与第五步的CMainFrame换成自定义的类名(这里我用CMyTestObject来代表自定义类)是不能正常工作的。原因在于在发送消息的SendMessage函数中的第一个参数是要响应消息对应的HWND类型的窗体句柄,而CMyTestObject类中的m_hWnd中在没有调用CWnd::Create之前是没有任何意义的,也就是没有调用CWnd::Create或CWnd::CreateEx函数时,CWnd不对应任何窗体,消息处理不能正常运作。
所以,又一个重要的结论,在自定义类能够处理任何消息之前一定要确保m_hWnd关联到一个窗体,即便这个窗体是不可见的。那么有人说,在自定义类的构造函数中调用Create函数就行了,不错,当然也可以在别处调用,只要确保在消息发送之前。但是,Create的调用很有说法,要注意两个地方,第一个参数是类的名称,我建议最好设为NULL;第五个参数是父窗体对象的指针,这个函数指定的对象一定要存在,我建议最好为整个程序的主窗体。还有很多人问第六个参数的意义,这个参数关系不大,是子窗体ID,用于传给父窗体记录以便识别。如下是我的自定义类的构造函数:
CMyTestObject::CMyTestObject()
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),::AfxGetMainWnd(),1234);
} //一定要在生成主窗体后使用,在主窗体完成OnCreate消息的处理后
CMyTestObject::CMyTestObject(CWnd *pParent)
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),pParent,1234);
}
不能如下调用Create,因为此时CMyTestObject不关联任何窗体,所以this中的m_hWnd无效:
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),this,1234);
这时上面四、五两步修改成:
BEGIN_MESSAGE_MAP(CMyTestObject, CWnd)
ON_MESSAGE(WM_MYMSG,OnMyMsgHandler)
END_MESSAGE_MAP()
LRESULT CMyTestObject::OnMyMsgHandler(WPARAM w,LPARAM l)
{
AfxMessageBox("My Messge Handler in My Self-Custom Class!");
return 0;
}
在类外部发出消息:
CMyTestObject *test=new CMyTestObject();
::SendMessage(test->m_hWnd,WM_MYMSG,0,0);
在类内部某个成员函数(方法)中发出消息:
::SendMessage(m_hWnd,WM_MYMSG,0,0);
最后一个问题便是容易产生警告错误的窗体回收,自定义的类要显式调用窗体销毁,析构函数如下:
CMyTestObject::~CMyTestObject()
{
CWnd::DestroyWindow();
}
1、在stdafx.h中加入一行代码
#define WM_MY_MESSAGE (WM_USER+100) //定义自已的消息
2、在xxxDlg.h(xxx表示你建立的项目名)中加入
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //用于对自定义消息的处理(作为CxxxDlg类的成员函数)
3、在xxxDlg.cpp中加入
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //用于将消息与消息处理函数联系起来(注意:此行代码应加到BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间)。
4、在xxxDlg.cpp中加入
LRESULT CtestMessageDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
....
}//上述代码为消息处理函数的具体实现
Doc/View Application:
第一步:定义消息。
推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
#define WM_MY_MESSAGE (WM_USER+100) |
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam) { // TODO: 处理用户自定义消息 ... return 0; } |
class CMainFrame:public CMDIFrameWnd { ... // 一般消息映射函数 protected: // {{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnTimer(UINT nIDEvent); afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //}}AFX_MSG DECLARE_MESSAGE_MAP() } |
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_TIMER() ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
在引发或发出消息的地方只用写上:
::SendMessge(::AfxGetMainWnd()->m_hWnd,WM_MYMSG,0,0);
到此,自定义消息完毕,这是好多网上文章都写的东西。大家会发现上面代码是在CMainFrame类中实现的,但是如果要用自定义类,就没有那么简单了。显然把第四步与第五步的CMainFrame换成自定义的类名(这里我用CMyTestObject来代表自定义类)是不能正常工作的。原因在于在发送消息的SendMessage函数中的第一个参数是要响应消息对应的HWND类型的窗体句柄,而CMyTestObject类中的m_hWnd中在没有调用CWnd::Create之前是没有任何意义的,也就是没有调用CWnd::Create或CWnd::CreateEx函数时,CWnd不对应任何窗体,消息处理不能正常运作。
所以,又一个重要的结论,在自定义类能够处理任何消息之前一定要确保m_hWnd关联到一个窗体,即便这个窗体是不可见的。那么有人说,在自定义类的构造函数中调用Create函数就行了,不错,当然也可以在别处调用,只要确保在消息发送之前。但是,Create的调用很有说法,要注意两个地方,第一个参数是类的名称,我建议最好设为NULL;第五个参数是父窗体对象的指针,这个函数指定的对象一定要存在,我建议最好为整个程序的主窗体。还有很多人问第六个参数的意义,这个参数关系不大,是子窗体ID,用于传给父窗体记录以便识别。如下是我的自定义类的构造函数:
CMyTestObject::CMyTestObject()
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),::AfxGetMainWnd(),1234);
} //一定要在生成主窗体后使用,在主窗体完成OnCreate消息的处理后
CMyTestObject::CMyTestObject(CWnd *pParent)
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),pParent,1234);
}
不能如下调用Create,因为此时CMyTestObject不关联任何窗体,所以this中的m_hWnd无效:
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),this,1234);
这时上面四、五两步修改成:
BEGIN_MESSAGE_MAP(CMyTestObject, CWnd)
ON_MESSAGE(WM_MYMSG,OnMyMsgHandler)
END_MESSAGE_MAP()
LRESULT CMyTestObject::OnMyMsgHandler(WPARAM w,LPARAM l)
{
AfxMessageBox("My Messge Handler in My Self-Custom Class!");
return 0;
}
在类外部发出消息:
CMyTestObject *test=new CMyTestObject();
::SendMessage(test->m_hWnd,WM_MYMSG,0,0);
在类内部某个成员函数(方法)中发出消息:
::SendMessage(m_hWnd,WM_MYMSG,0,0);
最后一个问题便是容易产生警告错误的窗体回收,自定义的类要显式调用窗体销毁,析构函数如下:
CMyTestObject::~CMyTestObject()
{
CWnd::DestroyWindow();
}
Dialog_based Application:
自定义消息可分为四步1、在stdafx.h中加入一行代码
#define WM_MY_MESSAGE (WM_USER+100) //定义自已的消息
2、在xxxDlg.h(xxx表示你建立的项目名)中加入
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //用于对自定义消息的处理(作为CxxxDlg类的成员函数)
3、在xxxDlg.cpp中加入
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //用于将消息与消息处理函数联系起来(注意:此行代码应加到BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间)。
4、在xxxDlg.cpp中加入
LRESULT CtestMessageDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
....
}//上述代码为消息处理函数的具体实现
相关文章推荐
- customize your own memory allocator (1)
- HOWTO: How to Provide Your Own DllMain in an MFC Regular DLL
- Customize your own Silverlight control
- HOWTO: How to Provide Your Own DllMain in an MFC Regular DLL
- HOWTO: Provide Your Own Window Class Name for an MFC Dialog Box
- customize your own memory allocator (2)
- customize your own rotation behavior
- Customize web.config sections and register your own configuration then get values in asp.net
- Customize Your Own Linux
- Using MC.exe, message resources and the NT event log in your own projects
- Milestone/A853/XT702/umts_sholes Compile your own Android ROM and Customize your own linux kernel
- MFC里面ON_COMMAND和ON_MESSAGE的区别
- Creating your own header file in C
- Build your own linux system by yourself
- Android.mk for your own module
- Creating Your Own Personalized Sewing Label
- Use System.Transactions namespace to manage your own resources
- MFC中ON_COMMAND,ON_MESSAGE,ON_NOTIFY的区别
- MFC BEGIN_MESSAGE_MAP()
- XBalloonMsg - a non-MFC balloon-shaped message box