深入淺出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(找到)

         //執行消息處理函數。

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章