MFC中的消息类型:
普通消息:也就是以WM_开头,除了WM_COMMAND以外的消息,这类消息在WM_USER以下的是系统消息,WM_USER以上的可以由 用户自己定义
命令消息:就是WM_COMMAND,也就是一些菜单、工具栏中的消息,包括快捷键,这类消息处理的机制与其他以WM_开头的消息处理 机制不同,它具有一条层次明确的消息流动路径
1.如果一个类要响应消息,应该具备什么条件?
答:能够响应消息的类必须都从CCmdTarget类中派生,因为只有以这个类中提供了消息的框架和处理机制。
而CWnd类,CWinApp类、CDocument类、CDocTemplate类等都是CCmdTarget的派生类,即子类;而CFrameWnd类、CView类、CDialog类等都是从CWnd中派生的,其实也是CCmdTarget的子孙,所以都能够响应消息,但是响应消息的种类不太相同。
如果该类要求响应普通的Windows消息,那就要求自定义的类必须从CWnd中派生。
如果该类要求响应命令消息,那么自定义的类可以从CCmdTarget中派生
2.普通消息的处理机制是怎样的?
答:消息发出者直接发给对应CWnd的窗体句柄,由CWnd负责消息的响应。
所以这类消息必须同一个CWnd类对应,更精确的说必须与一个HWND类型的窗体句柄相对应。
CWnd类或其子类没有调用CWnd::Create或CWnd::CreateEx函数时,CWnd类不对应任何窗体,消息处理不能正常运作。
3.如何自定义MFC消息?
答:在.h中做的工作:
第一步要声明消息:
#define WM_MYMSG WM_USER+8
第二步要在类声明中声明消息映射:
DECLARE_MESSAGE_MAP()
第三步要在类声明中定义消息处理函数:
afx_msg LRESULT MyMsgHandler(WPARAM,LPARAM);
在.cpp中做的工作:
第四步要实现消息映射:
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_MESSAGE(WM_MYMSG,OnMyMsgHandler)
END_MESSAGE_MAP()
第五步要实现消息处理函数(当然可以不实现):
LRESULT CMainFrame::OnMyMsgHandler(WPARAM w,LPARAM l)
{
AfxMessageBox("Hello,World!");
return 0;
}
在引发或发出消息的地方只用写上:
::SendMessge(::AfxGetMainWnd()->m_hWnd,WM_MYMSG,0,0);
4.以上是继承自CWnd类的自定义消息处理,如何自定义一个由CObject类派生的类来处理消息呢?
答:一个重要的结论,在自定义类能够处理任何消息之前一定要确保m_hWnd关联到一个窗体,即便这个窗体是不可见的。
在自定义类的构造函数中调用Create函数,当然也可以在别处调用,只要确保在消息发送之前。
Create的调用,要注意两个地方,第一个参数是类的名称,最好设为NULL,
第五个参数是父窗体对象的指针,这个函数指定的对象一定要存在,最好为整个程序的主窗体。
程序实例:
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();
}