我们先看看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相同,就不存在视图之间的命令消息传递了!