深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递) .

命令传递(Command routing

     消息如果是仅仅从派生类流向父类,那就非常简单了。然而MFC用来处理消息的C++类,并不是单线发展的。document/view也具有处理消息的能力。因此,消息应该有横向流动的机会。

     MFC对消息循环的规定为:

    1:若是一般的windows消息(WM_xx)则一定是由派生类流向基类。

    2:如果是WM_COMMAND消息,就非常复杂了。要区分接受者的类型:

      1:接受者若为Frame窗口:处理次序为:View-> Frame窗口本身->CWinApp类。

  2:接受者若为View :处理次序为:View本身->Document;

  3:接受者若为Document:处理次序为:Document本身->Document template

    因此,接下来我们的任务就是仿真以上的消息传递路线。

    以下为需要添加的函数:

    全局函数AfxWndProc,它是整个消息循环的起始点,本来应该在CWinThread::Run中被调用,每调用一次就推送一个消息。模拟windows的disPatch函数。

 LRESULT AfxWndPro(HWND hWnd,UINT nMsg,WPARAM  

                        wParam,LPARAM lParam,CWnd *pWnd)

{

   cout<<"AfxWndProc()"<<endl;

   return  AfxCallWndProc (pWnd,hWnd,nMsg,wParam,lParam);

}

LRESULT AfxCallWndProc(CWnd*pWnd,HWND hWnd,UINT nMsg,

                            WPARAM wParam,LPARAM lParam)

{

   cout<<"AfxCallWndProc"<<endl;

LRESULT lResult=pWnd->windowProc(nMsg,wParam,lParam);

return lResult;

}

全局函数AfxCallWndProc用于调用接受消息的类的消息处理函数。pWnd->WindowProc调用哪个函数,取决于pWnd指向的对象类型。

如果pWnd指向CMyFrameWnd对象,则调用CFrameWnd::WindowProc。因为CFrameWnd斌没有改写WindowProc,因此调用的是CWnd::WindowProc。。

    如果pWnd指向CMyView对象,那么调用CView::windowProc。而CMyView没有改写WIndowProc所以调用的是CWnd::WindowProc

    在CWnd::windowProc中,首先判断消息是否为WM_COMMAND消息,

    如不是,则传递给父类进行处理。

    如果是WM_COMMAND消息,CWnd::windowProc调用OnCommand。此函数为虚函数。有以下几种情况:

       1:如果this指向CMyFrameWnd对象,则调用的是CFrameWnd::OnComamnd

       2:如果this指向CMyView对象,那么调用的是CView::OnCommand。因为CView并没有改写OnComamnd所以调用的是CWnd::OnCommand

bool CFrameWnd::OnComamnd(WPARAM wParam,LPARAM lParam)

{

   cout<<"CFrameWnd::OnCommand()"<<endl;

   return CWnd::OnCommand(wParam,lParam);

}

bool CWnd::OnComamnd(WPARAM wParam,LPARAM lParam)

{

   cout<<"CWnd::OnComamnd()"<<endl;

   return OnCmdMsg(0,0);

}

    OnCmdMsg仍然是虚函数,

    1:如果this指向CMyFrameWnd对象,那么调用的是CFrameWnd::OnCmdMsg

    2:如果this指向CMyView对象,则调用CView::OnCmdMsg

    3:如果this指向CMyDoc对象,则调用CDocument::OnCmdMsg

4:如果this指向CMWinApp对象,则调用CWinApp::  nCmdMsg。因为CWinApp没有改写OnCmdMsg因此调用的是CCmdTarget::OnCmdMsg

Bool CFrameWnd::OnCmdMsg(UINT nID,int nCode)
{

cout<<"CFrameWnd::OnCmdMsg()"<<endl;

CView*pView=GetActiveView();

if(pView->OnCmdMsg(nID,nCode))//处理则返回否则继续传递。

   return true

if(CWnd::OnCmdMsg(nID,nCode))

  return true;

CWinApp*pApp=AfxGetApp();

if(pApp->OnCmdMsg(nID,nCode)

   return true;

return fasle;

}

bool CView::OnCmdMsg(UINT nID,int nCode)

{

  cout<<"CView::OnCmdMsg()"<<endl;

   if(CWnd::OnCmdMsg(nID,nCode))

     return true;

   bool bHandled=false;

   bHandled=m_pDocument->OnCmdMsg(nID,nCode);

   return bHandled;

}

Bool CDocument::OnCmdMsg(UINT nID,int nCode)

{

    cout<<"CDocument::OnCmdMsg()"<<endl;

    if(CCmdTarget::OnCmdMsg(nID,nCode))

     return true;

    return false;

}

     真正的消息传递路径是从OnCmdMsg开始的。在每个类的OnCmdMsg函数中,会调用其他类的OnCmdMsg函数,从而决定每个消息的传递路径。

     如果消息在前一个OnCmdMsg中被处理,就不会继续传递。如果没有被处理,则会继续沿着路径传递下去。无论如何,最终消息的比对是在CCmdTarget类中进行的,只是调用GetMessageMapthis指针不同,会决定调用哪个类的消息映射表。理解这一点很重要!!!

bool CCmdTarget::OnCmdMsg(UINT nID,int nCode)

{

   cout<<"CCmdTarget::OnCmdMsg()"<<endl;

   for(pMessageMap=GetMessageMap();pMessageMap;

             pMessageMap=pMessageMap->pBaseMessageMap()

    {

       If(找到)

         //执行消息处理函数。

    }

}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值