WM_NOTIFY

来源:互联网 发布:php redis抢红包源代码 编辑:程序博客网 时间:2024/06/07 06:51
1、WM_NOTIFY的由来。
对于窗口上的控件。控件上的行为会交由窗口处理,也就是控件(或者说系统为控件)发送一个消息通知窗口,这个消息就是WM_NOTIFY.其对应的处理函数是虚函数
OnNotify,所以可以在窗口的OnNotify中给出处理。如果想让控件自己处理,可以重载控件的OnChildNotify函数。

即:
窗口实现OnNotify
控件派生类,并重载OnChildNotify。

消息的路由是:点击控件->窗口OnNotify->控件OnChildNotify。其中窗口传给控件的过程就是所谓的消息反射。


如果采用方法1,至此,消息就完成了,不会再反给窗口。

(1)方法1
BOOL CDlgbase3Dlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
    // TODO: Add your specialized code here and/or call the base class
    if (wParam == IDC_LIST1)
    {
        NMHDR *pNMHDR = (NMHDR*)lParam;
        if (pNMHDR->code == NM_CLICK)
        {
            OutputDebugString("parent NM_CLICK");
        }
    }
    return CDialog::OnNotify(wParam, lParam, pResult);
}

BOOL CMyClistCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
    // TODO: Add your specialized code here and/or call the base class
    if (message == WM_NOTIFY)
    {
        NMHDR *pNMHDR = (NMHDR*)lParam;

        if (pNMHDR->code == NM_CLICK)
        {
            OutputDebugString("child NM_CLICK");
        }
        //return FALSE;
    }
    return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);
}

(2)方法2

如果要自由控制“控件处理完后是否窗口还可以继续处理”,则需要重写OnNotify。

#include <afxpriv.h>
#include "f:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\AFXIMPL.H"

......

BOOL CDlgbase3Dlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
        // TODO: Add your specialized code here and/or call the base class
    ASSERT(pResult != NULL);
    NMHDR* pNMHDR = (NMHDR*)lParam;
    HWND hWndCtrl = pNMHDR->hwndFrom;
    
    if (pNMHDR->code == NM_CLICK)
    {
        OutputDebugString("parent NM_CLICK 1");
    }

    if (ReflectLastMsg(hWndCtrl, pResult))
        return TRUE;

    if (pNMHDR->code == NM_CLICK)
    {
        OutputDebugString("parent NM_CLICK 2");
    }

    UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
    int nCode = pNMHDR->code;

    AFX_NOTIFY notify;
    notify.pResult = pResult;
    notify.pNMHDR = pNMHDR;
    return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), &notify, NULL);
}
BOOL CMyClistCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
    // TODO: Add your specialized code here and/or call the base class
    if (message == WM_NOTIFY)
    {
        NMHDR *pNMHDR = (NMHDR*)lParam;

        if (pNMHDR->code == NM_CLICK)
        {
            OutputDebugString("child NM_CLICK");
            return TRUE;

        }
    }
    return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);
}

注:ReflectLastMsg函数内部实际调用了控件的OnChildNotify。因此,就可以通过OnChildNotify的返回值来决定窗口的处理。


2.ON_**_REFLECT

在1的描述中,可以看作是一种半手工的方式实现了消息反射(窗口通过ReflectLastMsg调用控件的OnChildNotify)。

实际上,MFC已经提供了一种更方便的方式,也就是真正的消息映射,即在classwizard中前面带有"="的消息。通过classwizard就可以添加。

如。ClistCtrl派生类CMyListCtrl的NM_CLICK消息。

ON_NOTIFY_REFLECT(NM_CLICK, OnClick)

 afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);

void CMyClistCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
    // TODO: Add your control notification handler code here
    OutputDebugString("child reflect");
    *pResult = 0;
}

但是,这种方式有个缺陷,那就是,窗口无法再通过消息宏ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList1)得到通知消息。

如果,既想控件处理,也想窗口也处理,那么窗口仍然要重载OnNotify函数,在这里面截取消息。所以这样的话,倒不如直接用方法1了。

原创粉丝点击