WM_NOTIF消息――子窗口的倾诉与父窗口的倾听

来源:互联网 发布:apache 401认证 编辑:程序博客网 时间:2024/04/28 06:21

 

WM_NOTIF消息
――子窗口的倾诉与父窗口的倾听
    所谓通知消息 是指在一个包含子窗口的窗口中,如果子窗口发生了一些事情,需要告诉父窗口时所发送的一种消息,为了通俗易懂,我们将子窗口发送消息与父窗口的响应的过程称之为子窗口的倾诉,和父窗口的倾听两个过程。
1.子窗口的倾诉
   首先我们先要了解子窗口述说的方式,以及它要说的内容:
        显然,一个父窗口中可能有许多子窗口,那么在某个子窗口要告诉父窗口一些事情时就需要明确其身份,以便父窗口对其进行确认,那么在这个通知消息中就需要包含能鉴别其身份的信息这就是ID 和 窗口句柄;
    一个子窗口在不同的情况下想告诉其父窗口的事情可能有所不同,那么在一次通知的过程中,还要必须告诉其父窗口:我这次是来告诉你什么事的,这就是消息类型,这个可以由用户用#define MYCTRL_MYMESSGETYPE 来自己定义一个类型,当然MFC也提供了一些基本类型。
    子窗口既然发送消息的目的是告诉父窗口一些事情,那么显然这些事情需要一起被包含进去。但是对于不同的子窗口它们“要说的话”可能有多有少,无论怎么样,所有的信息都不应该被遗漏。
    显然这三种内容中,子窗口的ID,和消息的类型是每次子窗口与父窗口进行一次交谈中所必不可少的,如果少了ID,父窗口不知道是谁在与它说话,如果少了消息类型,它就不知道子窗口想要告诉它什么类型的事情。我们称这两个信息为基本信息,其他的为附加信息
    这些信息怎么样被传送?
要传送这些消息显然要使用不同的数据结构,那么现在来看一下这些信息是如何被组织的:
MFC中基本信息是包含在一个NMHDR的结构体中的,这个结构形式如下:
typedef struct tagNMHDR
{
    HWND      hwndFrom;      //窗口句柄
    UINT_PTR idFrom;        //子窗口的ID
    UINT      code;         // 子窗口自定义的消息的类型 一般是通过
                                      // #define   MYCTRL_MYMESSGETYPE 定义的一个整数    
}   NMHDR;
    其他信息的组织:
    如果子窗口除了以上的基本信息需要组织,那么它就要自己定义一些自己的信息结构来附加到以上的基本信息之后,这样组成一个大的信息结构,以便一起被传送到父窗口。
    通常情况下:我们应该这样定义一个消息包的结构:
    typedef struct tagNM_GRIDVIEW {
        NMHDR hdr;      //  ******基本信息****** 它必须被摆在第一位  
        int   iRow;           //附加信息
        int   iColumn;     //附加信息
        …             
    } NM_YOURMESSAGE;
   
要说的话都组织好了,下面看子窗口如何与父窗口建立联系,并把它想说的话告诉父窗口:
    首先,子窗口肯定是在它自己的窗口里面发生了一些事情才有这个需要去告诉其父窗口,不然它肯定不会突然之间就自言自语起来,所以我们首先应该弄清楚是什么让这个子窗口“想要发话”了。
    比如说:子窗口里面产生了一个鼠标单击,这时子窗口想在这个事情发生的时候把一些事情告诉其父窗口,这就是子窗口要向父窗口倾诉的最原始的欲望,那么我们该怎么样去满足它这个欲望呢?(呵呵不要想歪了哦 :-))
    应该这样:我们在子窗口里面捕获这个鼠标单击事件,在这个事件的处理函数里面用一个函数SendMessage,将我们组织好的信息包发送到其父窗口中去。这样当这个子窗口里面再产生单击消息的时候,它就会自动的向其父窗口发送一个消息了。
    现在来看子窗口该怎么样向父窗口表述它的意愿呢:
首先我们肯定要得到父窗口的指针,不然我们向谁SendMessage呢?这一般可以由如下语句完成:
    CWnd *pParent = GetOwner();
有了pPrent以后我们就可以用它来pParent->SendMessage了。
下面再说:SendMessage
    该函数具有如下形式: SendMessage(UINT nMessage,WPARAM wParm,LPARAM lParm);
对于父窗口这既然是一个通知的话,那么nMessage 肯定是一个WM_NOTIFY 了,然后我们可以把子窗口的ID,放到wParam里面,然后把我们组织好的子窗口想说的话(即那个自定义的消息对象NM_YOURMESSAGE 的实体)的地址传给lParam。 这样当SendMessage 完成后,这消息就传出去了。剩下的事情就是父窗口该如何接受子窗口传过来的消息了。
2.倾听
    既然子窗口发话了,父窗口肯定需要某种方式来倾听它的话,上面提到了,子窗口向父窗口发送消息的时候所使用的类型是一个WM_NOTIFY 消息,那么显然在父窗口所在的类中应添加对WM_NOTIFY的响应函数。
    我们都知道MFC框架里面都有这样一组宏:
    BEGIN_MESSAGE_MAP( )
    END_MESSAGE_MAP()
其中包含了各种消息与其消息响应函数的映射;
    因为我们要响应的是 WM_NOTIFY 消息那么我们应该用如下形式来响应:
    ON_NOTIFY(在子控件里面定义的消息类型,子窗口ID,消息响应函数)
其中子控件里定义消息类型即:MYCTRL_MYMESSGETYPE
将上面的一行插入到消息映射宏中间。
同时在父窗口类的头文件里面加入下面的函数声明:
afx_msg void消息响应函数名(NMHDR *pNotifyStruct, LRESULT* pResult);
注意形式不能改变,这个函数就是当父窗口接受到子窗口发送的通知后应该做的事情,有了声明当然需要定义,在父窗口的CPP文件里面再加上这个函数的定义,在里面为所欲为吧!
    还有一点要说明的是:NMHDR *pNotifyStruct 这个指针就是指向我们自定义的消息对象NM_YOURMESSAGE 的实体的地址,只不过它还不是NM_YOURMESSAGE* 类型,你需要在你的实现函数里面把它强制转过来,NM_YOURMESSAGE* pMyMessage = (NM_YOURMESSAGE*) pNotifyStruct; 这样你就可以通过这个指针得到里面的数据啦,不会你自己在里面你都不知道吧???呵呵