VC切分窗口和多視圖


動態切分窗口:

動態切分窗口不能包含多於4個的窗格,要想得到4個以上的窗格,可以使用靜態切分窗口。動態切分窗口中的幾個窗格通常使用的是同一個視圖類。

創建動態切分窗口的方式共有3種:

1、在創建應用程序時,利用應用程序向導AppWizard的選項設置切分窗口

2、在創建了應用程序之后,通過添加組件對窗口進行切分

3、通過手動添加代碼編程的方式

 

使用AppWizard創建動態切分:

在MFC AppWizard Step 4 of 6對話框中,單擊Advanced按鈕,彈出Advanced Options對話框,選擇Window Styles選項卡,選中該頁的Use split window檢查框。

 

使用Splitter Bar組件:

選擇Project|Add To Project|Components and Controls...菜單,彈出Components and Controls Gallery對話框。雙擊Visual C++ Components目錄,選擇Splitter Bar項,插入Splitter Bar組件。

運行程序,打開【查看】菜單或者是【窗口】菜單,找不到前面使用AppWizard添加動態切分時的【分隔】菜單項。說明Splitter Bar組件的方式並沒有添加相應的菜單項,程序員可以自己添加上去。

注意:菜單的Caption(標題)可以隨便設定,但注意菜單項的ID必須是ID_WINDOW_SPLIT。ID_WINDOW_SPLIT是系統預先指定的,程序員一般不需要對此命令ID添加命令消息處理函數,就可以實現分隔,因為MFC應用程序框架中已經對該命令ID的消息進行了處理。

 

手動添加代碼:

1、在框架窗口類(對單文檔為主框架窗口,對多文檔為子框架窗口)中聲明一個CSplitterWnd類的成員變量m_wndSplitter

2、使用ClassWizard為框架窗口類添加OnCreateClient函數

注意:這里使用ClassWizard是重寫父類的虛函數,而不是添加消息處理

3、在OnCreateClient函數中調用CSplitterWnd類的成員函數Create產生動態切分

4、為應用程序添加一個ID為ID_WINDOW_SPLIT的菜單項

 

CSplitterWnd切分窗口類:

CSplitterWnd的成員函數中,有3個使用非常頻繁

1、Create函數

創建一個動態的切分窗口

2、CreateStatic函數

創建一個靜態的切分窗口

3、CreateView函數

為靜態切分窗口創建視圖窗口。在框架顯示一個靜態切分窗口之前,該窗口的所有視圖窗格都必須已被創建好。當動態切分窗口時,此函數被框架窗口自動調用。

 

靜態切分窗口:

靜態切分窗口是指在窗口創建時,切分窗口的窗格就已經創建好了,且窗格的數量和順序不會改變。最多可以支持16行×16列的窗口(即256個窗格),但是必須在應用程序中創建窗格,而且不同的窗口往往使用不同的視圖類。

 

創建靜態切分的步驟:

1、在框架窗口類中聲明一個CSplitterWnd類的成員變量m_wndSplitter

2、使用ClassWizard為框架窗口類添加OnCreateClient函數

3、在OnCreateClient函數中調用CSplitterWnd::CreateStatic產生靜態切分

4、在OnCreateClient函數中調用CSplitterWnd::CreateView產生每個切分的視圖窗口

 

為2DCAD應用程序添加靜態切分功能:

1、聲明切分窗口類對象m_wndSplitter

為主框架窗口類CMainFrame添加保護成員變量m_wndSplitter,代碼如下:

CSplitterWnd m_wndSplitter; //用於產生靜態切分

2、在框架窗口類中添加OnCreateClient函數

打開ClassWizard,選中MessageMaps選項卡,在Class name中選擇CMainFrame類,在ObjectIDs列表中選擇CMainFrame,在Message列表框中雙擊OnCreateClient項,為框架窗口添加OnCreateClient函數。

3、使用CreateStatic產生靜態切分

在OnCreateClient函數中添加如下代碼,就可以產生1×2的靜態切分窗口:

m_wndSplitter.CreateStatic(this, 1, 2);

4、使用CreateView產生每個視圖窗口

當用戶建立一靜態切分窗口時,應當同時建立窗口內的所以區域。可以在OnCreateClient函數中添加如下代碼來為第一行第一列的窗格產生視圖:

m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CMy2DCADView),

CSize(450, 250), pContext);

其中,第3個參數,視圖類的執行期類CRuntimeClass指針,可以用宏RUNTIME_CLASS來獲得。

注意:(1)必須為每一個靜態切分窗口創建視圖窗口,不能漏掉一個

(2)由於使用到了視圖類,因此,必須包含相應的類的頭文件。在MainFrm.cpp文件的開始部分包括以下兩個頭文件:

#include "2DCADDoc.h"
#include "2DCADView.h"

(3)產生靜態切分后,就不能再調用默認情況下的基類的OnCreateClient函數。因此,應該將下面的代碼刪除或者注釋掉:

// return CFrameWnd::OnCreateClient(lpcs, pContext);

最后,完整的CMainFrame::OnCreateClient函數代碼如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
//使用CreateStatic函數產生靜態切分
m_wndSplitter.CreateStatic(this, //父窗口指針
1, //行數
2); //列數

//使用CreateView為第1個窗格產生視圖
m_wndSplitter.CreateView(0, 0, //窗格的行、列序數
RUNTIME_CLASS(CMy2DCADView), //視圖類
CSize(450, 250), //初始化大小
pContext); //父窗口的創建參數

//使用CreateView為第2個窗格產生視圖
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMy2DCADView),
CSize(450, 250), pContext);

return 1; //不再調用基類的OnCreateClient函數
// return CFrameWnd::OnCreateClient(lpcs, pContext);
}

這時,用戶在一個視圖中所作的修改還不能立刻反映到其他視圖窗口中,還應添加相應的通知視圖重畫的代碼。

5、通知視圖重畫

文檔類有一個名為UpdateAllViews的函數,可以在文檔數據發生改變時通知所有的視圖窗口重畫。

在視圖類的OnLButtonDown函數中每個調用SetModifiedFlag函數的后面立即調用UpdateAllViews的函數,代碼如下:

...

pDoc->SetModifiedFlag(); //設置文檔“臟”標志
pDoc->UpdateAllViews(this); //重畫所有視圖

...

 

向當前工程中插入新類的兩種方式:

1、使用New Class對話框添加新類

(1)MFC ClassWizard中的New Class對話框

使用ClassWizard對話框中的Add Class...按鈕下的New...菜單項可以打開MFC ClassWizard對話框下的New Class對話框。這個對話框用來向當前工程中添加派生自MFC類庫的新類。

(2)通用的New Class對話框

單擊菜單命令Insert|New Class...可以打開一個通用的New Class對話框。實際上通用的New Class對話框相當於包含了3個對話框,用於產生幾乎所有不同的類。

2、使用插入包含類定義的文件到當前工程中

(1)將所需類的.h、.cpp文件復制到目標工程目錄下

(2)打開目標工程,單擊Project|Add To Project|Files...菜單項插入所需類的.h、cpp文件到目標工程中

(3)在所需類的.cpp文件中,去掉包含原來的工程的頭文件語句(比如2DCAD.h),添加包含目標工程的頭文件語句(比如Mut.h)

 

添加新的視圖類:

為2DCAD工程添加一個新的視圖類CTextView,單擊Insert|New Class...菜單項,在New Class對話框中確保Class type中選擇的是MFC Class,在Name編輯框中輸入CTextView,在Base class下拉列表中指定基類為CEditView。

添加了新的視圖類之后,就可以在框架窗口的OnCreateClient函數中調用CreateView函數時使用這個新視圖類了。接下來使用CTextView作為靜態切分窗口中第二個窗格的視圖類,在OnCreateClient函數中修改創建第二個窗口視圖的代碼如下:

//使用CreateView為第2個窗格產生視圖
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CTextView),//使用文本視圖類
CSize(250, 250), pContext);

由於使用到了新的視圖類,因此,應該在MainFrm.cpp文件的開始部分添加包含CTextView類頭文件的代碼:

#include "TextView.h"

注意:CEditView封裝了編輯框的功能,因此,如果要編寫文字處理軟件,可以使用CEditView作為視圖基類。CEditView最多支持64K的文本,如果需要支持更豐富的文本,可以使用CRichEditView作為視圖基類,但要包含頭文件afxrich.h。

 

表單視圖類CFormView:

CFormView就是可以在其中包含許多控件的視圖基類。這個類也像CDialog對話框類一樣,封裝了數據交換功能。甚至可以將CFormView理解為作為視圖的對話框。

1、創建對話框模板資源

(1)添加對話框模板,ID為IDD_FORMVIEW

(2)修改屬性

在Style選項卡中,設置Style選項為Child,Border選項為None,並去掉對Title Bar復選框的勾選。

注意:由於視圖類是一個子窗口,因此,必須設置Child選擇,否則程序不能正常運行。

(3)添加控件

刪掉默認的OK和Cancel按鈕,依次添加一個靜態文本、一個分組框和4個單選按鈕,同時為第一個單選按鈕添加上Group屬性。

注意:對一組單選按鈕來說,只需要對該組的第一個單選按鈕設置Group屬性就可以了。如果不設置Group屬性,就無法添加對應的成員變量。

2、產生CFormView的派生類

(1)使用ClassWizard為IDD_FORMVIEW對話框模板資源添加一個名為CColorForm的視圖類,注意選擇基類為CFormView

(2)在Member Variables選項卡中為IDC_RADIO1添加一個名為m_nColor的整型成員變量

注意:對一組單選按鈕只能對帶有Group屬性的按鈕增加一個成員變量,並且這個成員變量必須是int型。0表示選擇第一個,依次類推,-1表示未選擇。

在CColorForm構造函數中令成員變量m_nColor的初始值為0,表示選擇第一項。

3、修改切分窗口的視圖類

打開OnCreateClient函數,修改創建第二個窗口視圖的代碼如下:

//使用CreateView為第2個窗格產生視圖
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CColorForm),//使用表單視圖類
CSize(250, 250), pContext);

由於使用到了新的視圖類,因此,應該在MainFrm.cpp文件的開始部分添加包含CColorForm類頭文件的代碼:

#include "ColorForm.h"

可以像處理無模式對話框那樣,在表單視圖類中添加相應的消息處理函數。

 

一個多文檔多視圖的綜合示例:

下面綜合前面的知識,創建一個包含多文檔、多視圖、動態切分、三叉靜態切分以及可以支持多種文檔類型的綜合示例。

支持多種文檔類型:

在MFC應用程序中,要增加附加的文檔類型,大致可分為以下幾步:

1、使用ClassWizard添加新的文檔類、子框架窗口類以及視圖類(如果需要的話)

2、利用資源編輯器為新的文檔類型添加字符串資源

3、利用資源編輯器添加附加的圖標和菜單資源

4、創建新的文檔模板對象並加入到應用程序中

5、完成文檔的序列化以及視圖的顯示交互工作

下面為Mut添加支持多文檔類型的功能(此時Mut本身是一個空的具有動態切分窗口的多文檔程序):

1、添加新的文檔類、子框架窗口類和視圖類

一般來說,一個新的文檔類型所需要的文檔類、外邊框窗口類和視圖類有可能都不同於已經存在的類的,但也可能和現存的類相同(比如使用相同的子框架窗口)。因此,根據不同的需要會添加不同的類。這里,首先只添加一個新的視圖類和子框架窗口類,而文檔類則使用原來的類。

注意:多種文檔類型的各個文檔類一般是不同的

(1)添加新的視圖類的方法可以參加《向當先工程中插入新類的兩種方式》中的第二種方式,插入2DCAD程序中所用到的可以輸入簡單的文本的CTextView類。

(2)添加新的子框架窗口類CTextFrame,基類選擇為CMDIChildWnd。具體方法參加向當先工程中插入新類的兩種方式》中的第一種方式。

2、利用資源編輯器為新的文檔類型添加字符串資源

參照Mut應用程序已經存在的文檔模板字符串資源IDR_MUTTYPE,在字符串編輯器中增加一個新的字符串資源,指定ID為IDR_TEXTTYPE,內容為:

\nText\n文本視圖窗口\nText Files(*.txt)\n.txt\nTextDocument\nText Document

可見文檔模板字符串包含7個由“\n”結尾並分隔的子串,最后一個字符串后面不需要“\n”。這些子串描述了文檔的類型,它們的含義按照順序分別如下:

(1)窗口標題(2)文檔名(3)新建文檔類型名(4)過濾器名(5)文件擴展名(6)文檔類型ID(7)注冊文檔類型名

3、利用資源編輯器添加附加的圖標和菜單資源

(1)添加一個ID為IDR_TEXTTYPE的圖標,可以利用畫圖工具編輯之

(2)添加一個ID為IDR_TEXTTYPE的菜單,將IDR_MUTTYPE菜單資源下的【文件】、【編輯】、【查看】、【幫助】菜單復制到IDR_TEXTTYPE中。注意:可以使用右鍵菜單中的Insert Copy...,然后再修改。

注意:這些資源的ID必須同第二步中創建文檔模板字符串中所用的ID相同。

4、創建新的文檔模板對象並加入到應用程序中

在應用程序類CMutApp的InitInstance函數中,參照應用程序框架生成的代碼,創建另一個CMultiDocTemplate對象,並用CWinApp::AddDocTemplate成員函數注冊該模板對象。

//這是應用程序框架生成的代碼
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MUTTYPE,
RUNTIME_CLASS(CMutDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMutView));
AddDocTemplate(pDocTemplate);

//創建新的文檔模板對象
pDocTemplate = new CMultiDocTemplate(
IDR_TEXTTYPE, //新創建的字符串資源、圖標資源和菜單資源
RUNTIME_CLASS(CMutDoc), //仍舊使用原來的文檔類
RUNTIME_CLASS(CTextFrame), //新添加的子框架窗口類
RUNTIME_CLASS(CTextView)); //新添加的文本視圖類
//將新的文檔模板對象加入到應用程序中。
AddDocTemplate(pDocTemplate);

由於使用到了新的視圖類CTextView和新的子框架窗口類CTextFrame,因此應該在Mut.cpp文件的開始部分包含它們的頭文件:

#include "TextView.h"
#include "TextFrame.h"

注意:此時Mut程序就包含有兩個文檔模板對象,可以支持兩種不同的文檔了,但是,它們使用了相同的文檔類,而實際應用中應該使用不同的文檔類。

5、完成文檔的序列化以及視圖的顯示交互工作

最后,根據用戶的需要,可以為文檔類添加上數據保存以及序列化功能,為視圖類添加相應的顯示數據和交換功能。

多文檔的三叉靜態切分:

這三個窗口的排列方式類似“|—”形狀,所使用的視圖類分別類似前面2DCAD工程中創建的CColorForm類以及Mut工程中創建的CTextView類和CMutView類。

1、添加新的文檔模板對象

(1)添加新的視圖類和子框架窗口類

在Mut工程中創建一個和2DCAD工程中相同的CFormView類的派生類CColorForm。

注意:可以使用文件復制再插入的方法,還需要將所需的對話框資源模板以及控件的ID值定義都復制過來。

再添加一個派生自CMDIChildWnd類的CThreeFrame類,作為文檔的外邊框窗口。

(2)編輯資源

添加ID都為IDR_THREETYPE的三個資源,字符串資源,圖標資源和菜單資源。其中,字符串資源如下:

\nThree\n三叉切分窗口\nThree Files(*.thr)\n.txt\nThreeDocument\nThree Document

(3)創建新的文檔模板對象

在應用程序類CMutApp的InitInstance函數中,參照應用程序框架生成的代碼,創建另一個CMultiDocTemplate對象,並用CWinApp::AddDocTemplate成員函數注冊該模板對象。

//創建三叉靜態切分的文檔模板對象
pDocTemplate = new CMultiDocTemplate(
IDR_THREETYPE, //用於三叉靜態切分窗口的字符串資源、圖標資源和菜單資源
RUNTIME_CLASS(CMutDoc), //仍舊使用原來的文檔類
RUNTIME_CLASS(CThreeFrame), //新添加的三叉切分子框架窗口類
RUNTIME_CLASS(CColorForm)); //新添加的表單視圖派生類
//將新的文檔模板對象加入到應用程序中。
AddDocTemplate(pDocTemplate);

由於使用到了新的視圖類CColorForm和新的子框架窗口類CThreeFrame,因此應該在Mut.cpp文件的開始部分包含它們的頭文件:

#include "ColorForm.h"
#include "ThreeFrame.h"

2、添加三叉靜態切分

(1)在子框架窗口類CThreeFrame中添加兩個CSplitterWnd類的保護成員變量m_wndSplitter1和m_wndSplitter2,分別用於產生第一次靜態切分和第二次靜態切分。

(2)使用ClassWizard為CThreeFrame添加OnCreateClient成員函數。

(3)改寫OnCreateClient成員函數代碼如下:

BOOL CThreeFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class

//使用CreateStatic函數產生第一次靜態切分
m_wndSplitter1.CreateStatic(this, //父窗口指針
1, //行數
2); //列數,一行兩列

//使用CreateView為第1個窗格產生CColorForm視圖
m_wndSplitter1.CreateView(0, 0, //窗格的行、列序數
RUNTIME_CLASS(CColorForm), //表單視圖類
CSize(250, 250), //初始化大小
pContext); //父窗口的創建參數

//再次使用CreateStatic函數對第一次切分產生的第二個窗口靜態切分
m_wndSplitter2.CreateStatic(
&m_wndSplitter1, //父窗口是第一次的切分窗口
2, 1, //將這個窗口切分成兩行一列
WS_CHILD | WS_VISIBLE, //窗口風格
m_wndSplitter1.IdFromRowCol(0, 1)
//指出新切分的窗口是上一次分隔的第一行第二個窗口
);

//使用CreateView為第二次切分的第1個窗格產生視圖
m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CTextView),//使用文本視圖類
CSize(150, 120), pContext);

//使用CreateView為第二次切分的第2個窗格產生視圖
m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CMutView),//使用CMutView視圖類
CSize(250, 250), pContext);

return 1; //不再調用基類的OnCreateClient函數
// return CMDIChildWnd::OnCreateClient(lpcs, pContext);
}

可見產生第一次切分的方法是,先使用CreateStatic函數產生第一次切分,然后再使用CreateStatic函數對第一次切分所產生的窗口再次切分。

注意:第二次調用CreateStatic函數切分時,函數的參數有些變化:一是父窗口是第一次的切分窗口,二是ID必須是上次切分窗格的ID。

(4)在ThreeFrame.cpp文件的開始部分包含下列頭文件:

#include "MutDoc.h"
#include "MutView.h"
#include "TextView.h"
#include "ColorForm.h"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM