廢話不多說,直切主題。(以下的示例說明均以MDI作為敘述)
整個程序就相當於一個 文檔模板[CSingleDocTemplate/CMultiDocTemplate]列表,單文檔就是只有一個模板,多文檔就是有多個模板。
一個模板就包括:菜單[Menu]、文檔[Doc]、框架[Frame]、視圖[View]
注意,他們是一個整體。
看一下代碼:
CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_MDI_TETYPE, // 菜單資源ID RUNTIME_CLASS(CMDI_testDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDI_testView)); AddDocTemplate(pDocTemplate); // 放到模板列表中
當使用VC自動生成的代碼時,編譯運行,使用菜單“開始”->“新建”,會從模板列表中選擇一個模板進行創建一個“整體”,最初的話,會自動生成一個新的窗口,因為最初只有一個文檔模板(“整體”),所以,它自動就生成了一個。注意菜單ID,它是子框架的菜單,它與ChildFrame綁定在一起了。我們可以通過關閉所有的View窗口,就可以觀察到菜單改變了,MainFrame主框架和ChildFrame在默認的情況下,它們的菜單是不同的。
請做試驗:添加一個菜單,響應該菜單函數,代碼就是創建一個新的模板,並加入到列表:
CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_MDI_TETYPE, RUNTIME_CLASS(CMDI_testDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDI_testView)); AddDocTemplate(pDocTemplate);
再通過“開始”->“新建”,這個時候,你會不會發現,這個時候,就會有兩個模板供你選擇了,因為你已經又創建了一個模板。如下圖:
說完了他們一個整體性,接下來,我們就來說說一個整體中,各個部件的關系。
1)框架 (Frame)是視圖和文檔的載體,視圖是一個窗口,文檔則不是窗口,視圖是要顯示在框架中的。我們看一下窗口父子關系:
從上面這兩幅圖對比,可以看出,視圖“sfdjk”的父窗口是“MDIClient”即是類CChildFrame[它從CMDIClientWnd派生出來]的對象。
2)視圖是顯示文檔數據的窗口。這里可以看出,文檔負責管理數據,視圖負責將文檔中的數據顯示出來。我們可以看下視圖OnDraw的代碼:
void CMDI_testView::OnDraw(CDC* pDC) { CMDI_testDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here
}
通過GetDocument就獲取了文檔的指針,然后就能去文檔中取數據,並在OnDraw中顯示出來。我們要知道的是,視圖View是有一個文檔Document的指針的,這便是對應關系了。[文檔並不需要一個視圖指針,因為數據便是數據,它不需要去關心誰去顯示它,但是事實上,它保存有與它關聯的視圖指針]
很多時候,我們一個文檔可以會包含有多份不同類別的數據,而又想用不同的窗口顯示不同類別的數據,這個時候,可以創建多個視圖,一個文檔是可以包含多個視圖的。然后在程序中處理好視圖的切換即可。我們創建一個新的視圖時,如何與文檔關聯起來呢?見代碼[主框架中,而非子框架中]:
// 文檔和視圖關聯
CDocument* m_pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument(); // 這里為什么要獲取活動的文檔呢?
// 因為主框架有可能含有多個模板,就有可能有多個文檔[因為一個模板有一個文檔就足夠了,多出的文檔有可能是其它模板的]
// 所以要獲取活動的文檔 CCreateContext context; context.m_pCurrentDoc = m_pDoc; // 創建視圖 UINT nIDFORANOTHERVIEW = AFX_IDW_PANE_FIRST + 1; CRect rect; m_pAnotherView->Create(
NULL,
NULL,
WS_CHILD,
rect,
((CFrameWnd*)m_pMainWnd)->GetActiveFrame (),
nIDFORANOTHERVIEW,
&context);
通過 CCreateCContext對象進行關聯。注意:因為框架是視圖和文檔的載體,所以框架有必要提供接口:獲取活動文檔、獲取活動視圖 [這里要注意,文檔和視圖雖然是對應關系,或者說有一定的包含關系,但它們並不能互相管理對方,它們只能由框架(Frame)進行統一管理]。
視圖既然是顯示在框架上的,那二者又如何關聯起來呢?見代碼:
CChildFrame * pFrm = new CChildFrame();// 框架可以是你新建或者定制的框架類
CCreateContext context; context.m_pNewViewClass = RUNTIME_CLASS(CDemoView);// 視圖可以是你想顯示的視圖 // context.m_pCurrentDoc = m_pDoc;// m_pDoc 就是你要關聯到的文檔對象 // 也可以進行文檔的關聯
pFrm->LoadFrame(IDR_TEST2TYPE,WS_CHILD|WS_OVERLAPPEDWINDOW, this, &context);// 菜單資源你可以修改
pFrm->ShowWindow(SW_SHOW);// 顯示窗口
pFrm->InitialUpdateFrame(NULL,true);// 調用視圖的 OnInitialUpdate ()和框架的 ActiveFrame (),你可以在這里設置窗口的標題
最后來說一下他們之間的關系。
Frame框架可以:
1)獲取活動的Frame框架[如果沒有子框架,就返回它自己]
2)獲取活動的文檔
2)獲取/設置活動的視圖
Document文檔可以:
1)獲取Frame框架
2)增加/刪除視圖
3)更新視圖
4)設備所有從該文檔生成的Frame框架的標題
View視圖可以:[就它最可憐]
1)獲取它所關心的文檔
參考資料:http://blog.163.com/hzxjtx@126/blog/static/356533742009121105752954/