友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
深入浅出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章曾经以一个简单的
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!