轉自:http://blog.csdn.net/u011478505/article/details/11620145
靜態分割窗口與多視圖實例
所謂多視,是指在同一個框架窗口下同時顯示多個視圖。通過運用這種技術,可以在框架的有限的空間內同時提供給用戶更大的信息量,並且使得用戶界面更加的友好,增強了軟件的可操作性。
窗口分割的基本概念
按照分割的時機的不同,窗口分割可以分爲兩類:動態分割和靜態分割。
動態分割是指用戶可以動態的分割和合並窗口。動態分割最多可以有2行2列個窗口,並且所有的窗格只能使用同一種視圖類。
靜態分割是指窗口在創建時,分割窗格窗口的窗格已經創建好了,且窗格的數量和順序不會改變了,窗格爲一個分隔條所分割,用戶可以拖動分割條調整相應的窗格的大小。靜態分割窗口最多可以有16行16列的窗格,但是各個窗格可以使用不同的視圖類。
無論創建那一種分割,都必須在創建時指定最大的行數和列數,這些值是有CSplitterWnd對象進行管理。對於靜態分割,必須創建指定數目的所有窗格以填滿行和列。而對於動態分割,第一個窗格將在框架創建CSplitterWnd對象時自動創建。
窗口分割支持類CSplitterWnd
CSplitterWnd類主要爲窗口的風格提供了封裝,窗口被分廠各個窗格後,又該類的對象負責管理。對於windows而言,CSplitterWnd
是一個真正的窗口,它完全佔據了框架窗口的用戶區域,而視圖則佔據了分割窗口的牀片區域。CSplitterWnd窗口不參與命令傳遞機制。
使用時,CSplitterWnd對象通常爲其父框架窗口CFrameWnd或CMDIChildWnd(MID應用中)對象的內嵌成員。CSplitterWnd對象創建過程如下。
在父框架窗口中嵌入CSplitterWnd類的對象成員;
重載父框架窗口的CFrameWnd::OnCreateClient成員函數;
從上一步重載的函數內部調用Create創建動態分割窗口或者調用CreateStatic創建靜態的分割窗口。
下面介紹CsplitterWnd類的幾個常用的函數
創建動態分割窗口函數Create
該函數用於動態創建分割窗口,同時將該窗口與類CSplitterWnd相關聯,其生聲明如下:
BOOL Create(CWnd*pParentWnd, int nMaxRows, int MaxCol, SIZE sizeMin, CcreateContext* pContext, DOWRD dwStyle = WS_CHILD | WS_VISIBLE | WS_HSCROLL| WSVSCROLL | SPLS_DYNAMIC_SPLIT, UINT nID=AFX_IDW_PANE_FIRST);
各主要參數的含義如下:
pParentWnd:分割窗口的父框架窗口的指針
nMaxRows和你MaxCols:行與列的最大值,二者均不大於二
sizeMin:指定窗格被顯示時的最小值。例如拖動分割框的幅度小於相應的值時,窗格將不會顯示,但是可以調用該類的另外兩個成員對此值進行改變。
BOOL CMainFrame::onCreateClient(LPCREATESTRUCT lpcs,CcreateConText*pContext)
{
return m_wndSplitter.Create(this ,2,2, /*設置行與列的數目*/Csize(10,10), /*窗格顯示時最小值*/ pContext);
}
創建靜態分割窗口函數CreateStatic
該函數用於創建靜態分割窗口,同時將該窗口與類CSplitterWnd相關聯,其聲明如下:
BOOL CreateStatic(CWnd* pParentWnd, int nRows,int nCols, DWORD dwStyle=WS_CHILD|WSVISBLE,UINTnID=AFX_IDW_PANE_FIRST);
主要參數的含義如下:
pParentWnd:分割窗口的父框架窗口指針
nRows和nCols:行與列的最大值,二者均不大於16
dwStyle:窗口風格,默認爲子窗口可見,如果添加滾動條,則需另外設置WS_HSCROLL和WS_VSCROLL。
創建窗格視圖函數CreateView
CreateView函數爲靜態分割窗口創建窗格視圖,在框架顯示分割窗口之前,靜態分割窗口的所有窗格都必須創建完畢。其聲明如下:
Virtual BOOL CreateView(int row,intcol,CRuntimeClass* pViewClass,SIZE sizeInit, CcreateConText *pContext);
各個主要參數的含義如下:
row :分割窗口中新建視圖所在的行。
col:分割窗口中新建視圖所在的列。
pViewClass:新建視圖的CRuntimeClass的指針。
sizeInit:新建視圖的初始化大小。
創建靜態分割窗口,並指定各窗格的視圖的典型代碼如下:
BOOLCMainFrame::OnCreateClient(LPCREATESTRUCT lpcs,CcreateConText* pContext)
{
BOOLbCreateSpltr=m_wndSplitter.CreateStatic(this,2,1);//靜態分割
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(COneView),CSize(0,0),pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CAnotherView),CSize(0,0),pContext);
return (bCreateSpltr);
}
另外,CSplitterWnd還提供了一些用於獲取和設置窗格屬性的函數,常用的函數及其功能如下表。
CSplitterWnd類中的其他常用函數及實現的功能
成員函數 |
函數說明 |
GetColumnCount |
獲取窗口分割的窗格的列數 |
GetRowCount |
獲取窗口分割的窗格的行數 |
SetRowInfo |
爲窗格行設置最小寬和理想寬,行的最小值決定了行何時因爲太小而不能顯示 |
SetColnuInfo |
爲窗格列設置最小高和理想好,列的最小值決定了列何時因爲太小而不能顯示 |
OnDrawSplitter |
此函數有框架負責調用,主要用來繪製或者指定分割窗口的確切特性 |
OnInvertTracker |
使用設置分割條的屬性,該函數在調整窗格大小期間有框架負責調用 |
靜態分割與多視圖實例
實例說明
實例爲一個基於單文檔的MFc應用程序,通過靜態分割窗口的方式三叉切分窗口,即共有三個窗格。程序實現的功能是用戶可以輸入學生的信息,並添加到列表視圖中。程序最終運行的結果如下圖:
程序運行結果
其中左側的基本信息輸入的窗格採用的是CFormView類型的視圖,在用戶可以其中進行信息的錄入,單擊“提交”按鈕,數據就添加道文檔中了,並在右側的列表視圖中顯示。右側信息顯示的窗格採用的是CListView類型的視圖,顯示文檔中存儲的所有學生信息。而底部的窗格採用的是CEditView類型的視圖,用於提示用戶上一步添加的數據。下面介紹具體的實現過程。
創建工程
使用AppWizard創建一個基於單文檔的應用程序框架工程,工程名爲“Guo”,其餘的現象均採用默認設置。
添加視圖類
需要爲3個窗格添加3個視圖類。CLeftFormView、CTopListView、CBottomEditView,其基類分別爲CFormView、CListView和CEditView。
1、CLeftFormView類的實現
A、 添加對話框資源模板:添加CLeftFormView類之前,首先要向工程中添加CLeftFormView視圖中對話框模板,如下圖所示:
對話框模板的ID爲“IDD_DIALOG1”,其Style屬性設置爲“Child”,Bolder屬性設置爲“None”。
B、添加CLeftFormView類。執行“Insert”→“New Class”菜單命令,彈出“New Class”對話框,在其中的Name編輯框中輸入類名“CLeftFormView”,在Base Class列表框中選擇基類“CFormView”選項,在Dialog ID列表框中選擇“IDD_DIALOG1”對話框資源。單擊Ok即可實現CLeftFormView類的添加。
C、添加CLeftFormView類的相關資源:利用Class Wizard在CLeftFormView中,爲對話框模板的4個編輯控件分別添加CString類型的成員變量m_Num、m_Name、m_Magor、m_Home,併爲“提交”按鈕添加BN_CLICKED消息響應函數OnSubmit()。
2、CTopListView類的實現
同樣使用“New Class”對話框,添加CTopListView類,將其基類選擇類型爲CListView。然後使用Class Wizard重載該類的PreCreateWindow()函數,在其中定義列表視的類型,代碼如下:
BOOLCTopListView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code hereand/or call the base class
cs.style=cs.style|LVS_REPORT;// 設置成報告列表的顯示形式
return CListView::PreCreateWindow(cs);
}
使用Class Wizard重載CTopListView類的OnInitialUpdate()函數,在其中添加列表的表頭,代碼如下:
voidCTopListView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
// TODO: Add your specialized code hereand/or call the base class
CStringm_ColumnLabelStr[]={"學號","姓名","專業","籍貫"};
//表頭字段
CListCtrl& listctrl=GetListCtrl();//獲取列表的控件
DWORD dwStyle =listctrl.GetExtendedStyle();
dwStyle|= LVS_EX_FULLROWSELECT;
// 選中某行使整行高亮(只適用與report風格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;
dwStyle |=LVS_EX_UNDERLINEHOT;
listctrl.SetExtendedStyle(dwStyle);//列表風格
int width[6]={80,80,110,150};
for(int i=0;i<4;i++)
{
listctrl.InsertColumn(i,m_ColumnLabelStr[i],LVCFMT_LEFT,width[i]);//設置表頭
}
}
3、CBottomEidtView類的實現
同樣使用New Class對話框,添加CBottomEditView類,將其基類選擇爲“CEditView”。而後使用Class Wizard重載該類的OnInitialUpdate()函數,在其中實現初始化設置,代碼如下:
void CBottomEditView::OnInitialUpdate()
{
CEditView::OnInitialUpdate();
//TODO: Add your specialized code here and/or call the base class
CEdit &mEdit=GetEditCtrl(); //獲取編輯視圖的控件
mEdit.SetWindowText("等待用戶輸入學生的信息!");//設置顯示信息
mEdit.EnableWindow(FALSE);//編輯控件不可編輯
}
靜態分割窗口的實現
窗口的分割過程中是首先在主框架CMainFrame中,將窗口分割成上下兩個窗格,對應的視圖分別爲CGuoView和CBottomEditView。而後,再在CGuoView視圖中將窗格分爲左右兩個窗格,對應的視圖分別爲CLeftFormView和CTopListView,實現過程如下。
1、 在CMainFrame類的頭文件中,聲明一個CSplitterWnd類的成員變量m_wndSplitter1,用於第一個窗口的分割
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
CSplitterWnd m_wndSplitter1; //用於產生第一次的靜態的分割
2、 使用Class Wizard重載CMainFrame類的OnCreateClient()函數,在其中實現第一次的窗口分割。
BOOLCMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//TODO: Add your specialized code here and/or call the base class
CRect rect;
GetClientRect(&rect); //產生第一次靜態分割
m_wndSplitter1.CreateStatic(this, //父窗口指針
2,1); //行數與列數
m_wndSplitter1.CreateView(0,0, //窗格的行列序數
RUNTIME_CLASS(CGuoView),//視圖類
CSize(rect.Width(),rect.Height()-rect.Height()/5),pContext);//父窗口創建參數
m_wndSplitter1.CreateView(1,0,RUNTIME_CLASS(CBottomEditView),
CSize(rect.Width(),rect.Height()/5),pContext);
//不在調用基類的OncreateClient函數
return true;
}
包含相應的頭文件,在MainFrame.cpp文件的開始加入下列語句
#include "GuoView.h"
#include "BottomEditView.h"
3、 在視圖窗口類CGuoView的頭文件中聲明一個CSplitterWnd類的成員變量m_wndSplitter2,用於第二次窗口分割。
protected:
CSplitterWnd m_wndSplitter2; //用於第二次窗口的分割
4、 使用Class Wizard重載CGuoView類的OnCreateClient()和OnSize()函數,實現窗口第二次分割並設置窗格的大小。
int CGuoView::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(CView::OnCreate(lpCreateStruct) == -1)
return-1;
//TODO: Add your specialized creation code here
CRectrect;
GetClientRect(&rect); // 獲得窗口的創建信息指針
CCreateContext*pContext=(CCreateContext *)lpCreateStruct->lpCreateParams;
m_wndSplitter2.CreateStatic(this,1,2);//產生第二次的靜態分割
//爲第一個窗格產生視圖
m_wndSplitter2.CreateView(0,0,//窗口的行列序數
RUNTIME_CLASS(CLeftFormView),//視圖類
CSize(rect.Width()/4,rect.Height()),//
pContext);
//爲第二個窗格產生視圖
m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CTopListView),CSize(1,1),pContext);
return0;
}
void CGuoView::OnSize(UINT nType, intcx, int cy)
{
CView::OnSize(nType,cx, cy);
//TODO: Add your message handler code here
CRect rect;
GetClientRect(&rect);
intx=rect.Width();
inty=rect.Height();
m_wndSplitter2.MoveWindow(-2,-2,x,y+3);
m_wndSplitter2.SetColumnInfo(0,x/4,0); //左邊窗格位置
m_wndSplitter2.SetColumnInfo(1,x-x/4,0); //右邊窗格位置
m_wndSplitter2.RecalcLayout();
}
至此,窗口的分割完成,編譯運行程序,就會發現三叉窗口已經實現。如果在編譯連接程序的時候出現如下面的錯誤:
c:\documents and settings\chenqi\桌面\guo\guoview.h(23) :error C2143: syntax error : missing ';' before '*'
c:\documents and settings\chenqi\桌面\guo\guoview.h(23) :error C2501: 'CGuoDoc' : missing storage-class or type specifiers
c:\documents and settings\chenqi\桌面\guo\guoview.h(23) :error C2501: 'GetDocument' : missing storage-class or type specifiers
則可以在CGuoView類頭文件的前面加上這麼一句class CGuoDoc; 就沒有問題了。
窗格視圖與文檔的交互
窗口中分割的各窗格視圖對應着同一文檔對象CGuoDoc,每個CView派生類都已經繼承了GetDocument()函數,因此只要在調用後進行類型的強制轉換就可以獲取文檔的對象。如:CGuoDoc* pDoc=(CGuoDoc*)GetDocument();
本實例在文檔對象CGuoDoc中,通過數組類對象存儲學生信息,當在CLeftFormView視圖中,輸入學生信息單擊“提交”按鈕時,就將輸入信息寫入文檔中的數組對象,並重繪各視圖。
1、在CGuoDoc類的頭文件中聲明數組對象和數據修改標記,如下:
Public:
CStringArray infoArray[4];
bool add;
並在構造函數中將add的值初始化爲FALSE。
2、在CLeftFormView類的按鈕響應函數OnSubmit()中,添加代碼實現控件數據的保存並更新所有視圖。
voidCLeftFormView::OnSubmit()
{
//TODO: Add your control notification handler code here
UpdateData(TRUE);// 獲取對話框的控件數據
if(m_Num.IsEmpty()||m_Name.IsEmpty()) //判斷是否爲空
{ AfxMessageBox("學號和姓名不能爲空!");return; }
CGuoDoc*pDoc=(CGuoDoc*)GetDocument();// 獲取文檔
pDoc->infoArray[0].InsertAt(0,m_Num); // 輸入數據插入數據
pDoc->infoArray[1].InsertAt(0,m_Name);
pDoc->infoArray[2].InsertAt(0,m_Magor);
pDoc->infoArray[3].InsertAt(0,m_Home);
pDoc->add=true; //添加了數據
pDoc->UpdateAllViews(NULL); //更新所有視圖
m_Num=_T("");
m_Name=_T("");
m_Magor=_T("");
m_Home=_T("");
UpdateData(FALSE); //各控件的內容清空
}
包含CGuoDoc類的頭文件,在CLeftFormView.cpp文件開始加入下列語句:
#include "GuoDoc.h"
3、重載視圖類CTopListView和CBottomEditView中OnUpdate()函數,實現視圖更新。
void CTopListView::OnUpdate(CView*pSender, LPARAM lHint, CObject* pHint)
{
//TODO: Add your specialized code here and/or call the base class
CGuoDoc*pDoc=(CGuoDoc*)GetDocument(); //獲取文檔指針
if(pDoc->add) //添加了數據
{
CListCtrl& listctrl=GetListCtrl();// 獲取列表的控件
listctrl.DeleteAllItems(); //刪除所有項
for(inti=0;i<pDoc->infoArray[0].GetSize();i++) //列表框中插入數據
{
listctrl.InsertItem(i,pDoc->infoArray[0].GetAt(i));
listctrl.SetItemText(i,1,pDoc->infoArray[1].GetAt(i));
listctrl.SetItemText(i,2,pDoc->infoArray[2].GetAt(i));
listctrl.SetItemText(i,3,pDoc->infoArray[3].GetAt(i));
}
}
}
void CBottomEditView::OnUpdate(CView*pSender, LPARAM lHint, CObject* pHint)
{
//TODO: Add your specialized code here and/or call the base class
CGuoDoc* pDoc=(CGuoDoc*)GetDocument();// 獲取文檔指針
if(pDoc->add) // 添加了數據
{
CString str;
str="添加了學號爲"+pDoc->infoArray[0].GetAt(0)+"的學生信息!";
CEdit &mEdit=GetEditCtrl(); //獲取編輯視圖控件
mEdit.SetWindowText(str); //顯示信息
}
}
同樣需要在這兩個視圖類的資源文件中包含文檔對象的頭文件,如下:
#include "GuoDoc.h"
至此,實例開發結束,編譯運行工程,即可實現要求的結果。