友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第107部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


  CCmdTarget                 CWnd          CFrameWnd        CMyFrameWnd 

                                                                                                                    s 

                                                                                  ; ; ; ; ;       ; ; ; ; ; 



                                                                                                                    s 

                                                                               0;0;0;0;0;0      0;0;0;0;0;0         a 



                                ; ; ; ; ;       ; ; ; ; ;        ; ; ; ; ; 

        ; ; ; ; ;                                                                                                  g 

                              0;0;0;0;0;0     0;0;0;0;0;0      0;0;0;0;0;0                                          e 

     0;0;0;0;0;0 



                          CDocument       CMyDocument 



                                ; ; ; ; ;       ; ; ; ; ; 



                              0;0;0;0;0;0     0;0;0;0;0;0 



                       图9…3 当WM_PAINT 发生于View 窗口, 消息的流动路线。 



                                                                                                                     571 


…………………………………………………………Page 634……………………………………………………………

                   第篇    深入  MFC  程式設計 



             拐弯上溯(WM_MAND 命令消息) 



                   如果消息是WM_MAND,你看到了,CWnd::OnWndMsg                   (上节所述)另辟蹊跷,交 



                   由Onmand 来处理。这并不一定就指的是CWnd::Onmand,得视this 指针指向 



                   哪一种对象而定。在MFC 之中,以下数个类别都改写了Onmand 虚拟函数: 



                       class CWnd : public CCmdTarget 

                       class CFrameWnd : public CWnd 

                       class CMDIFrameWnd : public CFrameWnd 

                       class CSplitterWnd : public CWnd 

                       class CPropertySheet : public CWnd 

                       class COlePropertyPage : public CDialog 



                   我们挑一个例子来看。假设消息是从CFrameWnd 进来的好了,于是: 



                                     (        ) 

                   // in FRMWND。CPP  MFC 4。0 

                   BOOL CFrameWnd::Onmand (WPARAM wParam; LPARAM lParam) 

                    { 

                           。。。 



                           // route as normal mand 

                           return CWnd::Onmand (wParam; lParam); 

                    } 

                                       (       ) 

                   // in WINCORE。CPP  MFC 4。0 

                   BOOL CWnd::Onmand (WPARAM wParam; LPARAM lParam) 

                    { 

                           。。。 

                           return OnCmdMsg (nID; nCode; NULL; NULL); 

                    } 



                   这里调用的OnCmdMsg 并不一定就是指CWnd::OnCmdMsg,得看this 指针指向哪一种 



                   对象而定。目前情况是指向一个CFrameWnd 对象,而MFC 之中「拥有」OnCmdMsg 的 



                   类别(注意,此话有语病,我应该说MFC 之中「曾经改写」过OnCmdMsg 的类别)是: 



                       class CCmdTarget : public CObject 

                       class CFrameWnd : public CWnd 

                       class CMDIFrameWnd : public CFrameWnd 

                       class CView : public CWnd 

                       class CPropertySheet : public CWnd 

                       class CDialog : public CWnd 

                       class CDocument : public CCmdTarget 

                       class COleDocument : public CDocument 



572 


…………………………………………………………Page 635……………………………………………………………

                                                       第9章   訊息映射與命令繞行   



显然我们应该往CFrameWnd 追踪: 



                   (        ) 

// in FRMWND。CPP  MFC 4。0 

BOOL CFrameWnd::OnCmdMsg (UINT nID; int nCode; void* pExtra; 

        AFX_CMDHANDLERINFO* pHandlerInfo) 

{ 

        // pump through current view FIRST 

        CView* pView = GetActiveView(); 

        if (pView != NULL && pView…》OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                return TRUE; 



        // then pump through frame 

        if  (CWnd::OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                return TRUE; 



        // last but not least; pump through app 

        CWinApp* pApp = AfxGetApp(); 

        if (pApp != NULL && pApp…》OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                return TRUE; 



        return FALSE; 

} 



这里非常明显地兵分三路,正是为了实践MFC 这个Application Framework 对于命令讯 



息的绕行路线的规划: 



     命令消息接收物的类型        处理次序 



     Frame                          1。 View 

           窗口 

                                    2。 Frame  窗口本身 

                                    3。 CWinApp 对象 



    View                            1。 View 本身 

                                    2。 Document 



     Document                       1。 Document  本身 

                                    2。 Document Template 



         图9…4 MFC 对于命令消息WM_MAND 的特殊处理顺序。 



  让我们锲而不舍地追踪下去: 



                                                                                       573 


…………………………………………………………Page 636……………………………………………………………

                    第篇    深入  MFC  程式設計 



                                          (        ) 

                    // in VIEWCORE。CPP  MFC 4。0 

                    BOOL CView::OnCmdMsg(UINT nID; int nCode; void* pExtra; 

                            AFX_CMDHANDLERINFO* pHandlerInfo) 

                     { 

                        // first pump through pane 

                        if (CWnd::OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                            return TRUE; 



                        // then pump through document 

                        BOOL bHandled = FALSE; 

                        if (m_pDocument != NULL) 

                        { 

                            // special state for saving view before routing to document 

                            _AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); 

                            CView* pOldRoutingView = pThreadState…》m_pRoutingView; 

                            pThreadState…》m_pRoutingView = this; 

                            bHandled = m_pDocument…》OnCmdMsg (nID; nCode; pExtra; pHandlerInfo); 

                            pThreadState…》m_pRoutingView = pOldRoutingView; 

                        } 



                        return bHandled; 

                     } 



                    这反应出图9…4 搜寻路径中「先View 而后Document 」的规划。由于CWnd 并未改写 



                    OnCmdMsg,所以函数中调用的CWnd::OnCmdMsg,其实就是CCmdTarget::OnCmdMsg: 



                                         (        ) 

                    // in CMDTARG。CPP  MFC 4。0 

                    BOOL CCmdTarget::OnCmdMsg (UINT nID; int nCode; void* pExtra; 

                            AFX_CMDHANDLERINFO* pHandlerInfo) 

                     { 

                        。。。 

                        // look through message map to see if it applies to us 

                        for (pMessageMap = GetMessageMap(); pMessageMap != NULL; 

                             pMessageMap = pMessageMap…》pBaseMap) 

                        { 

                            lpEntry = AfxFindMessageEntry (pMessageMap…》lpEntries; nMsg; nCode; nID); 

                            if (lpEntry != NULL) 

                            { 

                                // found it 

                                return DispatchCmdMsg (this; nID; nCode; 

                                        lpEntry…》pfn; pExtra; lpEntry…》nSig; pHandlerInfo); 

                            } 

                        } 

                        return FALSE;   // not handled 

                     } 



574 


…………………………………………………………Page 637……………………………………………………………

                                                         第9章   訊息映射與命令繞行   



其中的AfxFindMessageEntry  动作稍早我已列出。 



当命令消息兵分三路的第一路走到消息映射网的末尾一个类别CCmdTarget,没有办法再 



 「节外生枝」,只能乖乖比对CCmdTarget 的消息映射表。如果没有发现吻合者,传回 



FALSE ,引起CView::OnCmdMsg 接下去调用m_pDocument…》OnCmdMsg 。如果有吻合 



者,调用全域函数DispatchCmdMsg : 



static BOOL DispatchCmdMsg (CCmdTarget* pTarget; UINT nID; int nCode; 

        AFX_PMSG pfn; void* pExtra; UINT nSig; AFX_CMDHANDLERINFO* pHandlerInfo) 

                // return TRUE to stop routing 

{ 

        ASSERT_VALID(pTarget); 

        UNUSED(nCode);   // unused in release builds 



        union MessageMapFunctions mmf; 

        mmf。pfn = pfn; 

        BOOL bResult = TRUE; // default is ok 

        。。。 

        switch (nSig) 

        { 

        case AfxSig_vv: 

                // normal mand or control notification 

                (pTarget…》*mmf。pfn_MAND)(); 

                break; 



        case AfxSig_bv: 

                // normal mand or control notification 

                bResult = (pTarget…》*mmf。pfn_bMAND)(); 

                break; 



        case AfxSig_vw: 

                // normal mand or control notification in a range 

                (pTarget…》*mmf。pfn_MAND_RANGE)(nID); 

                break; 



        case AfxSig_bw: 

                // extended mand (passed ID; returns bContinue) 

                bResult = (pTarget…》*mmf。pfn_MAND_EX)(nID); 

                break; 

        。。。 

        default:    // illegal 

                ASSERT(FALSE); 



                                                                                          575 


…………………………………………………………Page 638……………………………………………………………

                    第篇    深入  MFC  程式設計 



                                    return 0; 

                            } 

                            return bResult; 

                     } 



                    以下是另一路CDocument 的动作: 



                    // in DOCCORE。CPP 

                    BOOL CDocument::OnCmdMsg (UINT nID; int nCode; void* pExtra; 

                            AFX_CMDHANDLERINFO* pHandlerInfo) 

                     { 

                            if (CCmdTarget::OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                                    return TRUE; 



                            // otherwise check template 

                            if (m_pDocTemplate != NULL && 

                              m_pDocTemplate…》OnCmdMsg (nID; nCode; pExtra; pHandlerInfo)) 

                                    return TRUE; 



                            return FALSE; 

                     } 



                     图9…5 画出FrameWnd 窗口收到命令消息后的四个尝试路径。第3章曾经以一个简单的 



    
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!