今天在我的项目中遇到这样的需求,我想在点击工具栏某个自定义的视图切换按钮时,静态切分窗口中的某个视图被一个新视图替换(例如:CFormView被CEditView替换)。我开始的想法是:在那个视图按钮被点击的消息响应函数中发送WM_CREATE消息,引发OnCreate,然后是如下的调用次序:OnCreateHelper——OnCreateClient——CreateView,经过实践发现只有第一次切换时,WM_CREATE消息被发送并得到响应,后来切换就不灵了!
最初的想法往往是最不成熟的,后来又在CodeProject上面找到别人重写的CSplitterWnd类,可以replace某个视图,于是乎直接拿来用了,代码如下:
BOOL CUsefulSplitterWnd::ReplaceView(int row, int col,CRuntimeClass * pViewClass,SIZE size)
{
CCreateContext context;
BOOL bSetActive;
if ((GetPane(row,col)->IsKindOf(pViewClass))==TRUE)
return FALSE;
// Get pointer to CDocument object so that it can be used in the creation
// process of the new view
CDocument * pDoc= ((CView *)GetPane(row,col))->GetDocument();
CView * pActiveView=GetParentFrame()->GetActiveView();
if (pActiveView==NULL || pActiveView==GetPane(row,col))
bSetActive=TRUE;
else
bSetActive=FALSE;
// set flag so that document will not be deleted when view is destroyed
pDoc->m_bAutoDelete=FALSE;
// Delete existing view
((CView *) GetPane(row,col))->DestroyWindow();
// set flag back to default
pDoc->m_bAutoDelete=TRUE;
// Create new view
context.m_pNewViewClass=pViewClass;
context.m_pCurrentDoc=pDoc;
context.m_pNewDocTemplate=NULL;
context.m_pLastView=NULL;
context.m_pCurrentFrame=NULL;
CreateView(row,col,pViewClass,size,&context);
CView * pNewView= (CView *)GetPane(row,col);
if (bSetActive==TRUE)
GetParentFrame()->SetActiveView(pNewView);
RecalcLayout();
GetPane(row,col)->SendMessage(WM_PAINT);
return TRUE;
}
但是又出现了新的问题,视图切换后不能被初始化,即OnInitialUpdate函数没有被执行。调试运行,进入了CSplitterWnd::CreateView(int row, int col,CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext)发现如下代码:
BOOL bSendInitialUpdate = FALSE;
CCreateContext contextT;
if (pContext == NULL)
{
// if no context specified, generate one from the currently selected
// client if possible
CView* pOldView = (CView*)GetActivePane();
if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CView)))
{
// set info about last pane
ASSERT(contextT.m_pCurrentFrame == NULL);
contextT.m_pLastView = pOldView;
contextT.m_pCurrentDoc = pOldView->GetDocument();
if (contextT.m_pCurrentDoc != NULL)
contextT.m_pNewDocTemplate =
contextT.m_pCurrentDoc->GetDocTemplate();
}
pContext = &contextT;
bSendInitialUpdate = TRUE;
}
........
if (bSendInitialUpdate)
pWnd->SendMessage(WM_INITIALUPDATE);
如果pContext 为空则发送WM_INITIALUPDATE初始化,反之则不发送。下面是摘自MSDN中的一段:
When passed as an argument for window creation, as in CWnd::Create, CFrameWnd::Create, and CFrameWnd::LoadFrame, the create context specifies what the new window should be connected to. For most windows, the entire structure is optional and a NULL pointer can be passed.
也就是说MFC通过pContext 来判断是否是第一次创建该视图,如果是则初始化,不是则不初始化。所以我们可以把上面ReplaceView函数代码稍微改一下,把CreateView(row,col,pViewClass,size,&context);改为CreateView(row,col,pViewClass,size,NULL);即可。再次运行程序,通过!o(∩_∩)o...哈哈