程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> MFC視圖切換大全總結,mfc視圖大全

MFC視圖切換大全總結,mfc視圖大全

編輯:C++入門知識

MFC視圖切換大全總結,mfc視圖大全


單純視圖之間的切換

單文檔多視圖切換是我在學習MFC中遇到的一個老大難問題,在今天總算是一一破解了。我覺得視圖切換分為三個等級,第一是在未切分窗格的情況下切換視圖類;第二是在分割窗格的一個窗格內實行視圖切換;第三是在分割窗格和未分割之間的切換和視圖切換。

在MFC創建SDI的伊始,MFC默認的視圖類是CView,如果CView滿足你的需求,可以直接單擊finish,如果你不想讓CView成為你的默認視圖類,你可以在下圖這個地方修改。

如果你忘記了修改默認的視圖類這也沒關系,我們可以在代碼中改變:

在App類裡面有個函數叫InitInstance(),在這裡面有一段代碼

CSingleDocTemplate* pDocTemplate; 
pDocTemplate = new CSingleDocTemplate( 
IDR_MAINFRAME, 
RUNTIME_CLASS(Cprogram8Doc), 
RUNTIME_CLASS(CMainFrame), 
RUNTIME_CLASS(CView1)); //這裡更改你的默認視圖類,注意不要忘記包含頭文件哦 
if (!pDocTemplate) 
return FALSE; 
AddDocTemplate(pDocTemplate);

說完了默認視圖類的更改,我們現在進入主題。

1、首先創建你需要切換的視圖類,AddClass進入或者創建一個控件然後AddClass創建控件關聯類,後者適用於Form之類的控件。

2、控制之處,比如菜單項單擊、單擊鼠標什麼的,我是使用菜單項來切換窗口的

void CMainFrame::OnView1() 

// TODO: Add your command handler code here

SwitchToForm(IDD_FORMVIEW1);

}

void CMainFrame::OnView2() 

// TODO: Add your command handler code here

SwitchToForm(IDD_FORMVIEW2);

}

3、SwitchToForm這個函數主要用於視圖切換

在這個函數中主要做以下幾個動作:

1、獲得當前視圖類指針和需要轉換的視圖類指針,如果是第一次使用需要New一個,並且與文檔類關聯;

2、改變活動視圖;

3、顯示新視圖和隱藏舊視圖;

4、設置控件ID;

5、調整框架視圖。

void CMainFrame::SwitchToForm(int nForm) 

CView *pOldActiveView=GetActiveView(); //1 
CView *pNewActiveView=(CView*)GetDlgItem(nForm); 
if(NULL==pNewActiveView) 

switch(nForm) 

case IDD_FORMVIEW1: 
pNewActiveView=(CView*)new CView1; 
break; 
case IDD_FORMVIEW2: 
pNewActiveView=(CView*)new CView2; 
break; 
case IDD_FORMVIEW3: 
pNewActiveView=(CView*)new CView3; 
break; 
case IDD_FORMVIEW4: 
pNewActiveView=(CView*)new CView4; 
break; 
default: 
break; 

CCreateContext context; 
context.m_pCurrentDoc=pOldActiveView->GetDocument(); 
pNewActiveView->Create(NULL,NULL,WS_CHILD | WS_BORDER,CFrameWnd::rectDefault,this,nForm,&context); 
pNewActiveView->UpdateData(); 

SetActiveView(pNewActiveView); //2 
pNewActiveView->ShowWindow(SW_SHOW); //3 
pOldActiveView->ShowWindow(SW_HIDE); 
if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView1)) //4 
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW1); 
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView2)) 
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW2); 
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView3)) 
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW3); 
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView4)) 
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW4); 
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); 
RecalcLayout(); //5 

在看網上其他人的帖子的時候發現在RecalcLayout(); 前面還要加一句delete pOldActiveView;我自己覺得這樣有些浪費資源,視圖類創建完成了隱藏起來,用的時候重新顯示。這樣的方法應該比每次使用都要創建好一些。小弟不才,有討論的朋友可以聯系我。

帶有分割窗格的視圖切換

切換視圖第二層就是帶有分割窗格的視圖切換

分割窗格的視圖切換,我覺得難點是不容易在有限區域進行視圖切換。

1、首先分割窗格,這裡我不多解釋,詳情看下面鏈接;

2、再給每個視圖一個唯一的ID號;

m_splitter.CreateStatic(this,1,2); 
m_splitter.CreateView(0,0,RUNTIME_CLASS(CTree1),CSize(100,100),pContext); 
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm1),CSize(100,100),pContext); 
CWnd *pWnd=m_splitter.GetPane(0,1); 
m_pViews[0]=(CView*)m_splitter.GetPane(0,1); 
pWnd->SetDlgCtrlID(IDD_FORM1); 
pWnd->ShowWindow(SW_HIDE); 
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm2),CSize(100,100),pContext); 
pWnd=m_splitter.GetPane(0,1); 
m_pViews[1]=(CView*)m_splitter.GetPane(0,1); 
pWnd->SetDlgCtrlID(m_splitter.IdFromRowCol(0,1)); 
pWnd->ShowWindow(SW_SHOW); 
RedrawWindow(); 
return true;

注:我這裡CreateView一個新視圖,就覆蓋掉前一個視圖,最終顯示的是最後一個視圖,前面的視圖只是隱藏起來,等到使用的時候顯示出來就好了。返回值要覆蓋返回到基類的語句return CFrameWndEx::OnCreateClient(lpcs, pContext);將這句話注解,然後return true;

3、在哪裡激活切換功能自己設計,我使用的是菜單;

4、響應主要包括下面幾個步驟:

1、首先獲得窗格中的當前視圖;

2、使用IsKindOf判斷這個類是否是將要切換到的類;

3、獲得框架長寬和窗格長寬;

CView *pView=(CView*)m_splitter.GetPane(0,1); //1 
m_bTest=pView->IsKindOf(RUNTIME_CLASS(CForm2)); //2 
CRect rcFrame,rcClient; //3 
m_splitter.GetClientRect(&rcClient); 
GetClientRect(&rcFrame);

上面的全部是准備工作,下面才是真正的切換;

4、刪除原有視圖

5、創建當前視圖

6、調整框架

if(m_bTest) 

m_splitter.DeleteView(0,1); 
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm1),CSize(rcClient.Width(),rcFrame.Height()),NULL); 
m_splitter.RecalcLayout(); 

else 

m_splitter.DeleteView(0,1); 
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm2),CSize(rcClient.Width(),rcFrame.Height()),NULL); 
m_splitter.RecalcLayout(); 
}

仔細一看,貌似這個還要比單純視圖切換還要簡單一些,這也沒辦法,CSplitterWnd提供了這麼一個便捷的方法。

帶分割視圖與未分割視圖之間的切換

這個是三部曲中我認為最難的,並不是說程序有多麼難,只是想到這個切分方式真的不容易,今天就把這三部曲的最後一曲分享給大家,也為互聯網做一點貢獻。

首先說一下程序的思想,為分割窗口層專門獨立創建一個基於CFrameWnd的類,然後在這裡面寫分割視圖的代碼,再與其他未分割的視圖類進行切換。

下面我們來看一下實現的過程:

1、創建一個基於CFrameWnd的派生類CSplitterFrame;

2、添加要填充分割窗口的視圖類和與分割視圖切換的視圖類;

3、為這個派生類重載OnCreateClient函數,構造分割視圖

m_Splitter.CreateStatic(this,1,2); 
m_Splitter.CreateView(0,0,RUNTIME_CLASS(CLeftTree),CSize(300,0),pContext); 
m_Splitter.CreateView(0,1,RUNTIME_CLASS(CRightList),CSize(300,0),pContext); 
return true;

這裡我不解釋了,想必大家都很熟悉了,這裡我要說一點我自己犯過的錯誤。我本來想在這裡GetClientRect獲得窗口大小,但失敗了,左思右想不明白,後來才發現,這又不是CMainFrame,所以根本不能獲得,要是用API函數。

4、在CMainFrame類裡面添加框架和視圖類指針變量

CSplitterFrame *m_pSplitterFrame; //分割視圖框架指針 
CView *m_pView; //單獨視圖類,基於CView類 
CView *m_pForm; //單獨視圖類,基於CFormView類 
int m_nCurrentID; //記錄當前視圖

5、在CMainFrame類裡面重載OnCreateClient函數,創建視圖及分割框架

CRect rcClient; 
GetClientRect(&rcClient); 
m_pView=new CViewShow; 
m_pView->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,NULL,pContext); 
m_pView->ShowWindow(SW_SHOW); 
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); 
pContext->m_pNewViewClass=(CRuntimeClass*)m_pView; //設置默認視圖類 
m_pForm=new CFormShow; 
m_pForm->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,IDD_FORMSHOW,pContext); 
m_pForm->ShowWindow(SW_HIDE); 
m_pSplitterFrame=new CSplitterFrame; 
m_pSplitterFrame->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,NULL,0,pContext); 
m_pSplitterFrame->ShowWindow(SW_HIDE); 
return true;

6、創建視圖切換函數

bool CMainFrame::Switch(int nID) 

if(nID==m_nCurrentID) 
return false; 
switch(nID) 

case IDD_FORMSHOW: 
m_pForm->ShowWindow(SW_SHOW); 
m_pForm->SetDlgCtrlID(AFX_IDW_PANE_FIRST); 
m_pView->ShowWindow(SW_HIDE); 
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST+2); 
m_pSplitterFrame->ShowWindow(SW_HIDE); 
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST+1); 
m_nCurrentID=IDD_FORMSHOW; 
break; 
case AFX_IDW_PANE_FIRST+1: 
m_pSplitterFrame->ShowWindow(SW_SHOW); 
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST); 
m_pForm->ShowWindow(SW_HIDE); 
m_pForm->SetDlgCtrlID(IDD_FORMSHOW); 
m_pView->ShowWindow(SW_HIDE); 
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST+2); 
m_nCurrentID=AFX_IDW_PANE_FIRST+1; 
break; 
case AFX_IDW_PANE_FIRST+2: 
m_pView->ShowWindow(SW_SHOW); 
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST); 
m_pForm->ShowWindow(SW_HIDE); 
m_pForm->SetDlgCtrlID(IDD_FORMSHOW); 
m_pSplitterFrame->ShowWindow(SW_HIDE); 
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST+1); 
m_nCurrentID=AFX_IDW_PANE_FIRST+2; 
break; 
default: 
break; 

RecalcLayout(); 
return true; 
}

7、創建調用方法

void CMainFrame::OnForm() 

// TODO: Add your command handler code here 
Switch(IDD_FORMSHOW); 

void CMainFrame::OnView() 

// TODO: Add your command handler code here 
Switch(AFX_IDW_PANE_FIRST+2); 

void CMainFrame::OnSplitter() 

// TODO: Add your command handler code here 
Switch(AFX_IDW_PANE_FIRST+1); 
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved