4.Notify消息流程

1.简介

如果想响应Notify事件,在自己的窗口的 HandleMessage() 函数中必须调用CPaintManagerUI::MessageHandler(),该函数处理了绝大部分常用的消息响应。

DuiLib将发送的Notify消息分为了同步和异步消息。同步就是立即调用,异步就是先放到队列中,下次再处理(类似PostMessage与SendMessage)。

2.发送Notify消息

CPaintManagerUI中有个函数用于程序主动发送Notify消息:

  • CPaintManagerUI::SendNotify(CControlUI*, LPCTSTR, WPARAM, LPARAM, bool)

该函数将PostMessage与SendMessage两个函数的功能集成在一个函数中,通过最后一个bool参数来区分同步消息或者异步消息:true:异步消息,false:同步消息。同步消息可以立马被执行,在消息被处理后,SendNotify() 才能返回;异步消息是先放在消息队列中,然后 SendNotify() 直接返回,异步消息会在窗口函数收到下一条消息的时候被处理。详细可以看代码:

void CPaintManagerUI::SendNotify(CControlUI* pControl, LPCTSTR pstrMessage, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/, bool bAsync /*= false*/)
{
    //对消息进行了封装
    TNotifyUI Msg;
    Msg.pSender = pControl;
    Msg.sType = pstrMessage;
    Msg.wParam = wParam;
    Msg.lParam = lParam;

    //发送消息还得看下面这个函数
    SendNotify(Msg, bAsync);
}

void CPaintManagerUI::SendNotify(TNotifyUI& Msg, bool bAsync /*= false*/)
{
    Msg.ptMouse = m_ptLastMousePos;
    Msg.dwTimestamp = ::GetTickCount();
    if( m_bUsedVirtualWnd )
    {
        Msg.sVirtualWnd = Msg.pSender->GetVirtualWnd();
    }

    if( !bAsync ) 
    {
        // Send to all listeners
        if( Msg.pSender != NULL ) 
        {
            //控件本身处理此消息
            if( Msg.pSender->OnNotify ) 
                Msg.pSender->OnNotify(&Msg);
        }
        for( int i = 0; i < m_aNotifiers.GetSize(); i++ ) 
        {
            //同步消息,被立即执行
            static_cast<INotifyUI*>(m_aNotifiers[i])->Notify(Msg);
        }
    }
    else 
    {
        //将消息存到堆上去
        TNotifyUI *pMsg = new TNotifyUI;
        pMsg->pSender = Msg.pSender;
        pMsg->sType = Msg.sType;
        pMsg->wParam = Msg.wParam;
        pMsg->lParam = Msg.lParam;
        pMsg->ptMouse = Msg.ptMouse;
        pMsg->dwTimestamp = Msg.dwTimestamp;

        //异步消息,被放在消息队列中
        m_aAsyncNotify.Add(pMsg);
    }
}

3.异步消息被处理

异步消息的处理时机:在窗口过程被执行的时候,即执行窗口的 HandleMessage() 的时候,且在 HandleMessage() 中调用了 CPaintManagerUI::MessageHandler()。原因在于异步消息只在CPaintManagerUI::MessageHandler()中进行处理。如下代码,将其他与异步消息无关代码已简化,并将异步消息处理提出成了一个函数:

bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes)
{
    //异步消息处理
    handleAsyncNotifyMsg();

    // 消息过滤

    // 普通消息处理
    switch( uMsg ) 
    {
        case WM_APP + 1:
        case WM_CLOSE:
        case WM_ERASEBKGND:
        case WM_PAINT: //重要,负责绘制窗口中的各个控件
        ....
    }

    // 异步消息处理:此处是为了处理上面switch时可能产生的一些异步消息
    handleAsyncNotifyMsg();

    return false;
}

//异步消息处理:循环取出异步消息,依次处理
void handleAsyncNotifyMsg()
{
    TNotifyUI* pMsg = NULL;
    while( pMsg = static_cast<TNotifyUI*>(m_aAsyncNotify.GetAt(0)) ) 
    {
        m_aAsyncNotify.Remove(0);
        if( pMsg->pSender != NULL ) 
        {
            if( pMsg->pSender->OnNotify ) pMsg->pSender->OnNotify(pMsg);
        }
        for( int j = 0; j < m_aNotifiers.GetSize(); j++ ) 
        {
            static_cast<INotifyUI*>(m_aNotifiers[j])->Notify(*pMsg);
        }
        delete pMsg;
    }
}

4.窗口的 Notify(TNotifyUI& msg) 函数

// Listener interface
class INotifyUI
{
public:
    virtual void Notify(TNotifyUI& msg) = 0;
};

bool CPaintManagerUI::AddNotifier(INotifyUI* pNotifier)
{
    ASSERT(m_aNotifiers.Find(pNotifier)<0);
    return m_aNotifiers.Add(pNotifier);
}

从上可知,Notify() 函数为 INotifyUI 定义的一个接口函数,所有的窗口都可以实现该函数。通过利用函数 AddNotifier() 注册监听,即可以处理Notify消息。

通过搜索发现, Notify() 函数在以下地方被调用:

  • void CPaintManagerUI::SendNotify(TNotifyUI& Msg, bool bAsync /= false/);
  • bool CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes);

在上述第一个函数中,用于处理同步消息;在第二个函数中处理异步消息。而异步消息的入口也是 SendNotify() 函数,通过此函数将异步消息添加到队列中。依次可以得出结论:所有的notify消息都是通过 SendNotify() 函数来进入到notify消息处理中的。

5.结束

Duilib的所有消息类型如下:

#define DUI_MSGTYPE_MENU                   (_T("menu"))
#define DUI_MSGTYPE_LINK                   (_T("link"))

#define DUI_MSGTYPE_TIMER                  (_T("timer"))
#define DUI_MSGTYPE_CLICK                  (_T("click"))

#define DUI_MSGTYPE_RETURN                 (_T("return"))
#define DUI_MSGTYPE_SCROLL                 (_T("scroll"))

#define DUI_MSGTYPE_DROPDOWN               (_T("dropdown"))
#define DUI_MSGTYPE_SETFOCUS               (_T("setfocus"))

#define DUI_MSGTYPE_KILLFOCUS              (_T("killfocus"))
#define DUI_MSGTYPE_ITEMCLICK              (_T("itemclick"))
#define DUI_MSGTYPE_TABSELECT              (_T("tabselect"))

#define DUI_MSGTYPE_ITEMSELECT             (_T("itemselect"))
#define DUI_MSGTYPE_ITEMEXPAND             (_T("itemexpand"))
#define DUI_MSGTYPE_WINDOWINIT             (_T("windowinit"))
#define DUI_MSGTYPE_BUTTONDOWN             (_T("buttondown"))
#define DUI_MSGTYPE_MOUSEENTER             (_T("mouseenter"))
#define DUI_MSGTYPE_MOUSELEAVE             (_T("mouseleave"))

#define DUI_MSGTYPE_TEXTCHANGED            (_T("textchanged"))
#define DUI_MSGTYPE_HEADERCLICK            (_T("headerclick"))
#define DUI_MSGTYPE_ITEMDBCLICK            (_T("itemdbclick"))
#define DUI_MSGTYPE_SHOWACTIVEX            (_T("showactivex"))

#define DUI_MSGTYPE_ITEMCOLLAPSE           (_T("itemcollapse"))
#define DUI_MSGTYPE_ITEMACTIVATE           (_T("itemactivate"))
#define DUI_MSGTYPE_VALUECHANGED           (_T("valuechanged"))

#define DUI_MSGTYPE_SELECTCHANGED          (_T("selectchanged"))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值