我們先看看VC課上學的命令消息傳遞的路線:
命令消息接收者的類型 | 處理次序 |
Frame窗口 |
1.View 2.Frame窗口本身 3.CWinApp對象 |
View | 1.View本身 2.Document |
Document | 1.Document本身 2.Document Template |
前幾天在我的科技創新項目中遇到了這樣的問題:用資源編輯器在菜單欄中添加了一個菜單項,並在一個右視圖類中添加了消息響應,但是程序運行時,那個菜單項不可用;而在另外一個左視圖類中添加消息響應時沒有出現問題。
我的界面設計成靜態切分窗口,左視圖派生自CTreeView,右視圖派生自CFormView;右視圖類是在AppWizard中添加的,左視圖類是我自己在創建切分窗口的代碼中添加的:
if (!m_wndSplitter.CreateStatic(this, 1, 2)) return FALSE; if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CWellTreeView), CSize(150, 100), pContext) || !m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CWellFormView), CSize(200, 100), pContext)) { m_wndSplitter.DestroyWindow(); return FALSE; } return TRUE;
我原本以爲在AppWizard中添加的類會首先接收到命令消息,但結果卻不是那樣,因此我判斷第一個被創建的視圖首先接受到命令消息,也就是說本該CWellFormView接收的命令消息被CWellTreeView “攔截”了,類似於Frame窗口接收的命令消息被View“攔截”。View“攔截”Frame的消息是怎麼實現的呢?讓我們看看MFC原始碼:
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { CPushRoutingFrame push(this);
// 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學習,在CWellTreeView中重寫虛函數OnCmdMsg,添加很簡單的一段代碼即可:
BOOL CWellTreeView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // TODO: Add your specialized code here and/or call the base class CWellListView* listview=(CWellListView*)GetView(RUNTIME_CLASS(CWellListView)); if(listview!=NULL && listview->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo)) return TRUE; return CTreeView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }
接下來,CWellListView就可以響應命令消息了。嘿嘿,有點成就感!
要注意的是這兩個View是不同的類,如果你做一個切分窗口兩個VIew相同,就不存在視圖之間的命令消息傳遞了!