靜態分割窗口與多視圖實例

轉自: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"

至此,實例開發結束,編譯運行工程,即可實現要求的結果。

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