`
hcmfys
  • 浏览: 357610 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

消息

 
阅读更多

在MFC应用程序中传输的消息有三种类型:窗口消息、命令消息和控件通知。
窗口消息(Window Message)一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗
口等。通常,消息是从系统发送到窗口,或从窗口发送到窗口。
若需要窗口消息的完全的列表,请参考M F C文档。
命令消息
命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生,
并被发送到能处理该请求的类对象(如,装载文件、编辑文本和保存选项等)。
控件通知
通常,控件通知在某些重要事件发生时,由控件窗口发送到父窗口,如打开一个组合框。
控件通知为父窗口进一步控制子窗口提供了机会。例如,打开一个组合框时,父窗口可以用
组合框初建时得不到的消息填充它。
ON_COMMAND 和ON_MESSAGE都是将消息处理函数加入消息路由表中,但是ON_COMMAND对应的消息ID一直都是WM_COMMAND,而ON_MESSAGE的消息ID为ON_COMMAND的第一个参数
在MFC中,ON_COMMAND, ON_MESSAGE, ON_NOTIFY它们的区别。
ON_NOTIFY是控件向其父窗口发送消息处理的宏,ON_COMMAND是菜单和工具栏项处理消息的宏,ON_MESSAGE是处理自定义消息的宏
ON_COMMAND用来处理WM_COMMAND消息。老式的windows控件发送WM_COMMAND作为对父窗口的通知消息。另外,菜单,工具栏也向框架窗口发送WM_COMMAND消息。
ON_MESSAGE主要用来处理用户自定义消息。
对于某些新型的windows控件(如ListCtrl等),向父窗口发送通知消息时需要包含大量的信息,WM_COMMAND已不适应这种要求(因为WM_COMMAND的wparam和lparam都已经填满了),ON_NOTIFY主要用来处理这些新型的windows控件向父窗口的发送的WM_NOTIFY通知消息。
对这几个消息的理解要先了解一下Window消息的背景。
在Windows3.1里,控件会将mouse, keybord等等的消息通知它的父窗口, 使用的消息就只有WM_COMMAND, 事件种类和控件ID被包含在wParam中,控件的句柄包含在lParam中。由于wParam和 lParam已经满了,当控件要向父窗口发送其它特殊消息同时附带很多信息的时候就没有地方可以存放它们了。所以Windows3.1中定义了许多其它的消息种类,比如WM_VSCROLL, WM_CTLCOLOR等等,每种消息wParam,lParam中附带的信息是不同的。
当到了Win32后,控件的种类越来越多,当然不可以为每一个控件都定义一套消息,这样也不利于系统的扩充。所以在Win32中定义了唯一一个强大的消息WM_NOTIFY。当然WM_NOTIFY也遵守原来的消息规则,既只带参数wParam和lParam。唯一不同处在于,此时的lParam中传送的是一个NMHDR指针。不同的控件可以按照规则对NMHDR进行扩充,因此WM_NOTIFY消息传送的信息量可以相当的大,这个可以看看MSDN中的相关说明,TreeControl中就有很多这种消息。
现在就可以知道为什么有ON_MESSAGE,ON_COMMAND,ON_NOTIFY了。
ON_MESSAGE是处理所有的Windows的消息的,因为所有的消息都以相同的格式传送,也就是ID, WPARAM, LPARAM.
ON_COMMAND是专门处理WM_COMMAND消息的,这样我们就不用自己解开WM_COMMAND中wParam和lParam中传送的控件ID,事件种类,所有的都在MFC内部解决了。
ON_NOTIFY更是不用说了,看看他的处理函数,是不是把NMHDR解出来了。
这样一样就一目了然了,ON_COMMAND和ON_NOTIFY都可以用ON_MESSAGE来处理,只不过自己要多做很多事情。ON_COMMAND和ON_NOTIFY最好就不要互换了!

ON_COMMAND是菜单和工具栏项处理消息的宏
ON_MESSAGE是处理自定义消息的宏

ON_NOTIFY 是控件向其父窗口发送消息处理的宏

/////////////////////////////////////////////////////////////////////////////////////////////////////

对这几个消息的理解要先了解一下Window消息的背景。
在Windows3.1里,控件会将mouse, keybord等等的消息通知它的父窗口, 使用的消息就只有WM_COMMAND, 事件种类和控件ID被包含在wParam中, 控件的句柄包含在lParam中。由于wParam和 lParam已经满了,当控件要向父窗口发送其它特殊消息同时附带很多信息的时候就没有地方可以存放它们了。所以Windows3.1中定义了许多其它的 消息种类,比如WM_VSCROLL, WM_CTLCOLOR等等,每种消息wParam,lParam中附带的信息是不同的。
当到了Win32后,控件的种类越来越多,当然不可以为每一个控件都定义一套消息,这样也不利于系统的扩充。所以在Win32中定义了唯一一个强大的消息 WM_NOTIFY。当然WM_NOTIFY也遵守原来的消息规则,既只带参数wParam和lParam。唯一不同处在于,此时的lParam中传送的 是一个NMHDR指针。不同的控件可以按照规则对NMHDR进行扩充,因此WM_NOTIFY消息传送的信息量可以相当的大,这个可以看看MSDN中的相 关说明,TreeControl中就有很多这种消息。

现在就可以知道为什么有ON_MESSAGE ,ON_COMMAND, , ON_NOTIFY了。
ON_MESSAGE是处理所有的Windows的消息的,因为所有的消息都以相同的格式传送,也就是ID, WPARAM, LPARAM.
ON_COMMAND是专门处理WM_COMMAND消息的,这样我们就不用自己解开WM_COMMAND中wParam和lParam中传送的控件ID, 事件种类…(所有的都在MFC内部解决了:),当然方便了。
ON_NOTIFY更是不用说了,看看他的处理函数,是不是把NMHDR解出来了。

这样一样就一目了然了,ON_COMMAND和ON_NOTIFY都可以用ON_MESSAGE来处理,只不过自己要多做很多事情。ON_COMMAND和ON_NOTIFY最好就不要互换了!

几点说明:

1、ON_COMMAND(id,memberFxn)
此宏通过ClassWizard或手工插入一个消息映射。它表明那个函数将从一个命令用户接口(例如一个菜单项或toolbar按钮)处理一个命令消息。 当一个命令对象通过指定的ID接受到一个Windows WM_COMMAND消息时,ON_COMMAND将调用成员函数memberFxn处理此消 息。在用户的消息映射中,对于每个菜单或加速器命令(必须被映射到一个消息处理函数)应该确实有一个ON_COMMAND宏语句。

2、ON_MESSAGE(message,memberFxn)
指明哪个函数将处理一用户定义消息。用户定义消息通常定义在WM_USER到0x7FF范围内。用户定义消息是那些不是标准 Windows WM_MESSAGE消息的任何消息。在用户的消息映射中,每个必须被映射到一个消息处理函数。用户定义消息应该有一个 ON_MESSAGE宏语句。

3、ON_Update_COMMAND_UI(id,memberFxn)
此宏通常通过ClassWizard被插入一个消息映射,以指明哪个函数将处理一个用户接口更改命令消息。在用户的消息映射中,每个用户接口更改命令(比讯被映射到一个消息处理函数)应该有一个ON_Update_COMMAND_UI宏语句。
4、ON_VBXEVENT(wNotifyCode,memberFxn)
此宏通常通过ClassWizard被插入一个消息映射,以指明哪个函数将处理一个来自VBX控制的消息。在用户的消息映射中每个被映射到一消息处理函数的VBX控制消息应该有一个宏语句。
5、ON_REGISTERED_MESSAGE(nmessageVarible,memberFxn)
Windows的RegisterWindowsMesage函数用于定义一个新窗口消息,此消息保证在整个系统中是唯一的。此宏表明哪个函数处理已注册消息。变量nMessageViable应以NEAR修饰符来定义。

6、ON_CONTROL(wNotifyCode,id,memberFxn)
表明哪个函数将处理一个常规控制表示消息。控制标识消息是那些从一个控制夫发送到母窗口的消息。

ON_NOTIFY是针对WM_NOTIFY的消息宏,

WM_NOTIFY是针对 ListCtrl,TreeCtrl,TabCtrl等通用控件使用的消息 button,listbox等基本控件是不会用到这个消息的


利用ON_COMMAND()宏创建的自定义消息处理机制确实无法使用wParam与lParam参数,这是由于ON_COMMAND()宏决定的。如果需要使用wParam与lParam参数,那么应当使用ON_MESSAGE()宏,由它扩展生成的消息处理函数的原型中才有这两个参数。

在.H文件中需要加入#define WM_MYMSG WM_USER+5以自定义一个消息,并在消息处理映射表中加入afx_msg void OnMyMessage(WPARAM wParam, LPARAM lParam)进行自定义消息的处理函数声明,这个声明一定要放在DECLARE_MESSAGE_MAP()宏之前。

afx_msg void OnMyMessage(WPARAM wParam, LPARAM lParam); //自定义消息的处理函数声明在.CPP文件中的消息映射表(BEGIN_MESSAGE_MAP与END_MESSAGE_MAP宏之间的内容)中需要加入ON_MESSAGE(WM_MYMSG, OnMyMessage)宏在自定义消息与其处理函数间建立映射关系,并实现消息处理函数void CModelessDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)。

void CModelessDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
//从lParam中取出CString对象的指针,并将字符串内容在IDC_MSGEDIT中显示出来
{
CString* pStr = (CString*) lParam;
ASSERT(pStr != NULL);

CEdit* pEdit = (CEdit *) GetDlgItem(IDC_MSGEDIT);
ASSERT(pEdit != NULL);

pEdit->SetWindowText(*pStr);
}
///////////////////////////////////////////////////////////////////////////////////////////////

WM_NOTIF在WIN32中得到大量的应用,同时也是随着CommControl的出现WM_NOTIFY成为了CommControl的基本消息。可以这样说CommControl的所有的新增特性都通过WM_NOTIFY来表达。同时WM_NOTIFY也为CommControl的操作带来了一致性。
WM_NOTIFY消息中的参数如下:
idCtrl = (int) wParam;
pnmh = (LPNMHDR) lParam; 其中lParam为一个

typedef struct tagNMHDR
{
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR; 结构指针
从消息的参数我们已经可以分辩出消息的来源,但是这些信息还不足以分辩出消息的具体含义。所以我们需要更多的数据来得到更多的信息。MS的做法是对每种不同用途的通知消息都定义另一种结构来表示,同时这中结构里包含了struct tagNMHDR,所以你只要进行一下类型转换就可以得到数据指针。例如对于LVN_COLUMNCLICK消息(用于在ListCtrl的列表头有鼠标点击是进行通知),结构为;
typedef struct tagNMLISTVIEW{
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
} NMLISTVIEW, FAR *LPNMLISTVIEW;

在这个结构的最开始也就包含了struct tagNMHDR,所以在不损失数据和产生错误的情况下向处理消息的进程提供了更多的信息。
 

此外通过WM_NOTIFY我们可以一种完全一样的方式进行消息映射,如同在前几章中所见到的一样。
使用如下形式:ON_NOTIFY( wNotifyCode, id, memberFxn )。
处理函数也有统一的原型:afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result );
在MFC消息映射的内部将根据定义消息映射时所使用的wNotifyCode和WM_NOTIFY中参数中pnmh->code(pnmh = (LPNMHDR) lParam)进行匹配,然后调用相应的处理函数。

还有一点是利用WM_NOTIFY/ON_NOTIFY_REFLECT可以在窗口内部处理一些消息,从而建立可重用的控件。大家可以参考Build Reusable MFC Control Classes。目前我也准备在空闲时翻译这篇文章。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics