靜態切分窗口的替換與更新

 今天在我的項目中遇到這樣的需求,我想在點擊工具欄某個自定義的視圖切換按鈕時,靜態切分窗口中的某個視圖被一個新視圖替換(例如: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...哈哈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章