明輝手游網(wǎng)中心:是一個免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

深入知道MFC中的文擋/視結(jié)構(gòu)

[摘要]作者: 李澤宇 金剛 熊聯(lián)歡 姜軍   Visual C++ 6.0 以其功能強(qiáng)大、用戶界面友好而倍受程序員們的青睞。但是,在當(dāng)前的Microsoft 基本類庫4.2 版本中,大約有將近200 個類,數(shù)千個函數(shù),加之Microsoft 公司隱藏了一些技術(shù)細(xì)節(jié),使得人們深入學(xué)習(xí)MFC變得十分困難。 ...
作者: 李澤宇 金剛 熊聯(lián)歡 姜軍 

 Visual C++ 6.0 以其功能強(qiáng)大、用戶界面友好而倍受程序員們的青睞。但是,在當(dāng)前的Microsoft 基本類庫4.2 版本中,大約有將近200 個類,數(shù)千個函數(shù),加之Microsoft 公司隱藏了一些技術(shù)細(xì)節(jié),使得人們深入學(xué)習(xí)MFC變得十分困難。
  MFC的AppWizard可以生成三種類型的應(yīng)用程序:基于對話框的應(yīng)用、單文檔應(yīng)用(SDI)和多文檔應(yīng)用(MDI)。前兩者的結(jié)構(gòu)較簡單,本文不再贅敘。筆者擬從MFC中的文檔/視結(jié)構(gòu)入手,分析一些函數(shù)的流程,并解決編制MDI 應(yīng)用程序過程中的一些常見問題。
(一)、了解文檔/視結(jié)構(gòu)
  MFC應(yīng)用程序模型歷經(jīng)多年以有了相當(dāng)大的發(fā)展。有一個時期,它只是個使用應(yīng)用程序?qū)ο蠛椭鞔翱趯ο蟮暮唵文P。在這個模型中,應(yīng)用程序的數(shù)據(jù)作為成員變量保持在框架窗口類中,在框架窗口的客戶區(qū)中,該數(shù)據(jù)被提交顯示器。隨著MFC2。0的問世,一種應(yīng)用程序結(jié)構(gòu)的新方式----MFC文檔/視結(jié)構(gòu)出現(xiàn)了。在這種結(jié)構(gòu)中,CFrameWnd繁重的任務(wù)被委派給幾個不同類,實現(xiàn)了數(shù)據(jù)存儲和顯示的分離。一般情況下,采用文檔/視結(jié)構(gòu)的應(yīng)用程序至少應(yīng)由以下對象組成:
。應(yīng)用程序是一個CwinApp派生對象,它充當(dāng)全部應(yīng)用程序的容器。應(yīng)用程序沿消息映射網(wǎng)絡(luò)分配消息給它的所有子程序。
。框架窗口是一CfrmeWnd派生對象。
。文檔是一個CDocument派生對象,它存儲應(yīng)用程序的數(shù)據(jù),并把這些信息提供給應(yīng)用程序的其余部分。
。視窗是Cview派生對象,它與其父框架窗口用戶區(qū)對齊。視窗接受用戶對應(yīng)用程序的輸入并顯示相關(guān)聯(lián)的文檔數(shù)據(jù)。
通常,應(yīng)用程序數(shù)據(jù)存在于簡單模型中的框架窗口中。在文檔/視方式中,該數(shù)據(jù)移入稱為document的獨(dú)立數(shù)據(jù)對象。當(dāng)然,文檔不一定是文字,文檔是可以表現(xiàn)應(yīng)用程序使用的數(shù)據(jù)集的抽象術(shù)語。而用戶輸入處理及圖形輸出功能從框架窗口轉(zhuǎn)向視圖。單獨(dú)的視窗完全遮蔽框架窗口的客戶區(qū),這意味著即使程序員直接繪畫至框架窗口的客戶區(qū),視圖仍遮蔽繪畫,在屏幕上不出現(xiàn)任何信息。所以輸出必須通過視圖?蚣艽翱趦H僅是個視圖容器。
CDocument類對文檔的建立及歸檔提供支持并提供應(yīng)用程序用于控制其數(shù)據(jù)的接口。MDI應(yīng)用程序可以處理多個類型的文檔,每個類型的文檔擁有一個相關(guān)聯(lián)的文檔模板對象。文檔對象駐留在場景后面,提供由視圖對象顯示的信息。文檔至少有一個相關(guān)聯(lián)的視圖。視圖只能與一個文檔相關(guān)聯(lián)。
在文檔/視方式中,對象的建立是由文檔模板來管理的,它是CDocTemplate派生對象,建立并維護(hù)框架窗口,文檔及視。
MFC調(diào)用命令處理程序以響應(yīng)發(fā)生在應(yīng)用程序中的事件。命令發(fā)送的優(yōu)先級是:
活動的視圖->框架窗口->文檔->應(yīng)用程序->默認(rèn)窗口過程(DefWindowsProc)
總之,在文檔/視方式中,文檔和視是分離的,即:文檔用于保存數(shù)據(jù),而視是用來顯示這些數(shù)據(jù)。文檔模板維護(hù)它們之間的關(guān)西。這種文檔/視結(jié)構(gòu)在開發(fā)大型軟件項目時特別有用。
(二)、了解與文檔/視結(jié)構(gòu)有關(guān)的各種類之間的關(guān)系。
在文檔/視應(yīng)用程序中,CWinApp對象擁有并控制文檔模板,后者產(chǎn)生文檔、框架窗口及視窗。這種相互關(guān)系如圖(1)所示:
從用戶的角度來看,“視”實際上是一個普通的窗口。象其他基于Widnows應(yīng)用的窗口一樣,人們可以改變它的尺寸,對它進(jìn)行移動,也可以隨時關(guān)閉它。若從程序員的角度來看,視實際上是一個從MFC類庫中的Cview類所派生出的類的對象。文檔對象是用來保存數(shù)據(jù)的,而視對象是用來顯示數(shù)據(jù)的,并且允許對數(shù)據(jù)進(jìn)行編輯。SDI或MDI的文檔類是由Cdocument類派生出來的,它可以有一個或多個視類,而這些視類最終都是由Cview類派生出來的。視對象只有一個與之相聯(lián)系的文檔對象,它所包含的CView::GetDocument函數(shù)允許應(yīng)用在視中得到與之相聯(lián)系的文檔,據(jù)此,應(yīng)用程序可以對文檔類成員函數(shù)及公共數(shù)據(jù)成員進(jìn)行訪問。如果視對象接受到了一條消息,表示用戶在編輯控制中輸入了新的數(shù)據(jù),此時,視就必須通知文檔對象對其內(nèi)部數(shù)據(jù)進(jìn)行相應(yīng)的更新。
如果文檔數(shù)據(jù)發(fā)生了變化,則所有的視都必須被通知到,以便它們能夠?qū)λ@示的數(shù)據(jù)進(jìn)行相應(yīng)的更新。Cdocument::UpdateAllViews函數(shù)即可完成此功能。當(dāng)該函數(shù)被調(diào)用時,派生視類的CView::OnUpdate函數(shù)被觸發(fā)。通常OnUpdate函數(shù)要對文檔進(jìn)行訪問,讀取文檔數(shù)據(jù),然后再對視的數(shù)據(jù)成員或控制進(jìn)行更新,以便反映出文檔的變化。另外,還可以利用OnUpdate函數(shù)使視的部分客戶區(qū)無效,以便觸發(fā)Cview::OnDraw函數(shù),利用文檔數(shù)據(jù)來重新對窗口進(jìn)行繪制。
在MDI應(yīng)用程序中,可以處理多個文檔類型,即多個文檔模板,每個模板又可以有多個文檔,每個文檔又可以多視顯示。為管理方便,上一級往往保留了下一級的指針列表。如圖(2)所示:
解釋如下:
(1)、每個應(yīng)用程序類(CwinApp的派生類)都保留并維護(hù)了一份所有文檔模板的指針列表,這是一個鏈表結(jié)構(gòu)。應(yīng)用程序為所要支持的每個文檔類型動態(tài)分配一個CMultiDocTemplate 對象,
CmultiDocTemplate(UINT nIDResource,
CruntimeClass * pDocClass,
CruntimeClass * pFrameClass,
CruntimeClass * pViewClass );
并在應(yīng)用程序類的CWinApp::InitInstance成員函數(shù)中將每個CMultiDocTemplate對象傳遞給CWinApp::AddDocTemplate。 該函數(shù)將一個文檔模板加入到應(yīng)用程序可用文檔模板的列表中。函數(shù)原形為:
void AddDocTemplate(CdocTemplate * pTemplate);
應(yīng)用程序可以用CWinApp::GetFirstDocTemplatePostion獲得應(yīng)用程序注冊的第一個文檔模板的位置,利用該值來調(diào)用CWinApp::GetNextDocTemplate函數(shù),獲得第一個CDocTemplate對象指針。函數(shù)原形如下:
POSITION GetFirstDocTemplate( ) const;
CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;
第二個函數(shù)返回由pos 標(biāo)識的文檔模板。POSITION是MFC定義的一個用于迭代或?qū)ο笾羔槞z索的值。通過這兩個函數(shù),應(yīng)用程序可以遍歷整個文檔模板列表。如果被檢索的文檔模板是模板列表中的最后一個,則pos參數(shù)被置為NULL。
(2)、一個文檔模板可以有多個文檔,每個文檔模板都保留并維護(hù)了一個所有對應(yīng)文檔的指針列表。應(yīng)用程序可以用CDocTemplate::GetFirstDocPosition函數(shù)獲得與文檔模板相關(guān)的文檔集合中第一個文檔的位置,并用POSITION值作為CDocTemplate::GetNextDoc的參數(shù)來重復(fù)遍歷與模板相關(guān)的文檔列表。函數(shù)原形為:
viaual POSITION GetFirstDocPosition( ) const = 0;
visual Cdocument *GetNextDoc(POSITION & rPos) const = 0;
如果列表為空,則rPos被置為NULL.
(3)、在文檔中可以調(diào)用CDocument::GetDocTemplate獲得指向該文檔模板的指針。函數(shù)原形如下:
CDocTemplate * GetDocTemplate ( ) const;
如果該文檔不屬于文檔模板管理,則返回值為NULL。
(4)、一個文檔可以有多個視。每一個文檔都保留并維護(hù)一個所有相關(guān)視的列表。CDocument::AddView將一個視連接到文檔上,將該視加入到文檔相聯(lián)系的視的列表中,并將視的文檔指針指向該文檔。當(dāng)有File/New、File/Open、Windows/New或Window/Split的命令而將一個新創(chuàng)建的視的對象連接到文檔上時, MFC會自動調(diào)用該函數(shù),框架通過文檔/視的結(jié)構(gòu)將文檔和視聯(lián)系起來。當(dāng)然,程序員也可以根據(jù)自己的需要調(diào)用該函數(shù)。
Virtual POSITION GetFirstViewPosition( ) const;
Virtual CViw * GetNextView( POSITION &rPosition) cosnt;
應(yīng)用程序可以調(diào)用CDocument::GetFirstViewPosition返回與調(diào)用文檔相聯(lián)系的視的列表中的第一個視的位置,并調(diào)用CDocument::GetNextView返回指定位置的視,并將rPositon的值置為列表中下一個視的POSITION值。如果找到的視為列表中的最后一個視,則將rPosition置為NULL.
當(dāng)在文檔上新增一個視或刪除一個視時,MFC會調(diào)用OnChangeViewList函數(shù)。如果被刪除的視是該文檔的最后一個視,則刪除該文檔。
(5)、一個視只能有一個文檔。在視中,調(diào)用CView::GetDocument可以獲得一個指向視的文檔的指針。函數(shù)原形如下:
CDocument *GetDocument ( ) const;
如果該視不與任何文檔相,則返回NULL.
(6)、MDI框架窗口通過調(diào)用CFrameWnd::GetActiveDocument 可以獲得與當(dāng)前活動的視相連的CDocument 指針。函數(shù)原形如下:
virtual CDocument * GetActiveDocument( );
(7)、通過調(diào)用CFrameWnd::GetActiveView 可以獲得指向與CFrameWnd框架窗口連接的活動視的指針,如果是被CMDIFrameWnd框架窗口調(diào)用,則返回NULL。MDI框架窗口可以首先調(diào)用MDIGetActive找到活動的MDI子窗口,然后找到該子窗口的活動視。函數(shù)原形如下:
virtual Cdocument * GetActiveDocument( );
(8)、MDI框架窗口通過調(diào)用CFrameWnd::GetActiveFrame, 可以獲得一個指向MDI框架窗口的活動多文檔界面子窗口的指針。
(9)、CMDIChildWnd調(diào)用GetMDIFrame獲得MDI框架窗口(CMDIFrameWnd)。
(10)、CWinApp 調(diào)用AfxGetMainWnd得到指向應(yīng)用程序的活動主窗口的指針。
下面一段代碼,就是利用CDocTemplate、CDocument和CView之間的存取關(guān)系,遍歷整個文檔模板、文檔以及視。
CMyApp * pMyApp = (CMyApp *)AfxGetApp();
POSITION p = pMyApp->GetFirstDocTemplatePosition();
while(p!= NULL) {
CDocTemplate * pDocTemplate = pMyApp->GetNextDocTemplate(p);
POSITION p1 = pDocTemplate->GetFirstDocPosition();
while(p1 != NULL) {
CDocument * pDocument = pDocTemplate->GetNextDoc(p1);
POSITION p2 = pDocument->GetFirstViewPosition();
while(p2 != NULL) {
CView * pView = pDocument->GetNextView(p2);
}
}
}
(圖4)、遍歷整個文檔模板、文檔和視
在應(yīng)用程序的任何地方,程序員都可以調(diào)用AfxGetApp( )獲得應(yīng)用程序的對象指針。由于本文著重介紹文檔/視的關(guān)系,至于框架窗口之間的關(guān)系沒能列全,讀者可以查相應(yīng)的文檔。
(三)、了解CwinApp::OnFileNew、CwinApp::OnFileOpen和Window/New的程序流程。
(1)、CwinApp::OnFileNew和CwinApp::OnFileOpen函數(shù)的簡單流程。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
在CWinApp::OnFile/new 或CwinApp::OnFileOpen函數(shù)中,核心操作是CDocTemplate::OpenDocument函數(shù)。其函數(shù)原型為:
virtual CDocument* CDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE ) = 0;
圖(4)中星號標(biāo)注之后即是該函數(shù)的流程,簡要介紹如下:
(1)、CDocTemplate::CreateNewDocument函數(shù)創(chuàng)建一個新文檔,其類型與文檔模板相關(guān),并通過函數(shù)CDocTemplate::AddDocument加入該文檔模板的文檔指針列表中。此時,文檔類的構(gòu)造函數(shù)被執(zhí)行,程序可以在此進(jìn)行文檔的初始化。
(2)、函數(shù)CDocTemplate::CreateNewFrame調(diào)用MDI子窗口類(CMDIChildWnd)的構(gòu)造函數(shù),生成MDI子窗口對象。接著調(diào)用CMDIChildWnd::PreCreateWindow。然后,生成一個CCreateContext對象,(CcreateContext是MFC框架所使用的一種結(jié)構(gòu),它將構(gòu)成文檔和視的組件聯(lián)系起來。后文將詳細(xì)介紹之。)并將該對象值傳給CMDIChildWnd::OnCreateClient函數(shù)。MFC調(diào)用此函數(shù),用CCreateContext對象提供的信息創(chuàng)建一個或多個CView對象。此時,各視的構(gòu)造函數(shù)被依次調(diào)用。
(3)、接著,判斷l(xiāng)pszPathName是否為空。分為兩種情況:
(a)、若為空,則表明要創(chuàng)建一個新文檔:調(diào)用SetDefaultTitle函數(shù)裝載文檔的缺省標(biāo)題,并顯示在文檔的標(biāo)題欄中;然后執(zhí)行CDocument::OnNewDocument。該函數(shù)調(diào)用DeleteContents以保證文檔為空,然后置新文檔為清潔。可以重載該函數(shù)。
(b)、否則,表明要打開一個已存在的文檔:調(diào)用CDocument::OnOpenDocument打開指定的文件;執(zhí)行DeleteContext,保證文檔為空;調(diào)用CObject::Serialize讀入該文件的內(nèi)容。(程序員可在此進(jìn)行文件的讀入操作。當(dāng)然,也可以在CDocument::OnOpenDocument中讀入文件)。然后置文檔為清潔;最后,調(diào)用CDocTemplate::SetPathName,并把文件名加入到最近文件列表中。
(4)、調(diào)用CDocTemplate::InitialUpdateFrame函數(shù),使框架窗口中的各個視收到OnInitialUpdate調(diào)用?蚣艽翱诘闹饕暎ㄗ哟癐D等于AFX_IDW_PANE_FIRST的視)被激活。程序員可以在此對視對象進(jìn)行初始化。
(2)、Window/New命令的程序流程
當(dāng)主框架窗口上有子窗口時,選擇Window/New命令可以生成該活動子窗口的影象。它們有相同的文檔模板、相同的文檔。其流程如下:
 
 
 
 
執(zhí)行Window/New的過程與File/New的過程差不多。所不同的是,F(xiàn)ile/New須要創(chuàng)建一個新文檔,而Window/New則是獲得已存在的MDI子窗口的文檔。因此以前存在的視和New以后生成的視均為該文檔的視,都是該文檔的內(nèi)容的顯示。當(dāng)調(diào)用CDocument::UpdateAllViews函數(shù)時,它們(視)的OnUpdate函數(shù)都將被激活。此時,在該文檔的視指針列表中,將有多于一個的視(具體數(shù)目視Window/New執(zhí)行的次數(shù)而定)。讀者可以利用(圖3)中的代碼跟蹤程序結(jié)果。
 
(四)、幾種情況的討論
上面,筆者就MFC中文檔/視的關(guān)系進(jìn)行了分析,下面,筆者將結(jié)合具體情況進(jìn)行討論:
(1)、如何根據(jù)自己的要求來選擇文檔模板,及相應(yīng)的視和文檔。
在通常的MDI應(yīng)用程序中,只有一個文檔模板,程序員只能打開一種類型的文檔。因此,程序員只要調(diào)用File/New或者File/Open創(chuàng)建或者打開文檔即可,至于文檔、視和框架窗口之間的關(guān)系,由文檔模板在幕后控制,不須要對文檔模板進(jìn)行操作。但是,如果應(yīng)用程序需要處理多種類型的文檔,并且何時打開何種文檔均需程序員手工控制,此時,程序員必須對文檔模板進(jìn)行編程。
例如,筆者需要處理AVI和BMP兩種文件類型。AVI和BMP的數(shù)據(jù)存放格式不同,不能用同一的數(shù)據(jù)結(jié)構(gòu)來描述,因此,把它們的數(shù)據(jù)都存入一個文檔是不合適的。同時,由于AVI是圖象序列,BMP僅是一幅圖象,它們的顯示是肯定不一樣的,即它門的視不同;诖,筆者決定分別建立兩套文檔模板,兩套框架窗口,兩套文檔和兩套視,分別用于AVI和BMP的數(shù)據(jù)存放和顯示。程序可以根據(jù)用戶選擇的文件名來分別處理AVI和BMP。具體步驟如下:
(Step 1)、在應(yīng)用程序類(CWinApp)的派生類中增加文檔模板成員變量,以便對文檔模板進(jìn)行操作。
class C3dlcsApp : public CWinApp
{ 。。。 。。。
public:
CMultiDocTemplate * m_pAVIDocTemplate;
CMultiDocTemplate * m_pBMPDocTemplate;
}
(Step 2)、在主框架中增加菜單響應(yīng):
void CMainFrame::OnFileOpen() {
CFileDialog my(true);
if(my.DoModal()==IDOK) {
CString FileName = my.GetPathName();
CString FileExt = my.GetFileExt();
if((FileExt == "AVI") (FileExt == "avi")) {
CMyApp * pMyApp = (CMyApp *)AfxGetApp();
CMultiDocTemplate*pAVIDocTemplate=pMyApp->m_pAVIDocTemplate;
pAVIDocTemplate->OpenDocumentFile(FileName);
}
else if((FileExt == "BMP") (FileExt == "bmp")) {
CMyApp * p3dlcsApp = (CMyApp *)AfxGetApp();
CMultiDocTemplate* pDATDocTemplate=pMyApp->m_pBMPDocTemplate;
pDATDocTemplate->OpenDocumentFile(FileName);
}
else {
AfxMessageBox("Yor select a file not supported!");
return;
}
}
}
筆者把用戶輸入文件名的后綴作為分支條件,如果是AVI文件,則先獲得關(guān)于AVI文件的文檔模板,然后調(diào)用CDocTemplate::OpenUpdateFrame (lpszFileName)函數(shù)打開此文檔。正如前面所分析,此函數(shù)將依次生成新文檔,新框架,在CMDIChildWnd::OnCreateClient中創(chuàng)建視,最后向框架中所有的視發(fā)送初始化消息,使其顯示在屏幕上。如果是BMP文件,操作類似。
當(dāng)然,程序員也可以在程序的任何位置實現(xiàn)此操作:通過全局函數(shù)AfxGetApp 獲得應(yīng)用程序?qū)ο笾羔,從而獲得相應(yīng)的文檔模板指針。
由于由AppWizard生成的應(yīng)用程序會缺省調(diào)用CWinApp::OnFileNew,所以當(dāng)程序開始執(zhí)行時,會在主框架上顯示一個新的空窗口。如果想去掉這個空窗口,只須重載CWinApp::OnFileNew函數(shù),不許要任何代碼,即可。
 
(2)、切分窗口與文檔/視結(jié)構(gòu)
一個文檔可以有多個視,切分窗口即是表示多視的一種方法。 切分窗口是通過類CSplitterWnd來表示的,對Window來說,CSplitterWnd對象是一個真正的窗口,它完全占據(jù)了框架窗口的客戶區(qū)域,而視窗口則占據(jù)了切分窗口的窗片區(qū)域。切分窗口并不參與命令傳遞機(jī)制,(窗片中)活動的視窗從邏輯上來看直接被連到了它的框架窗口中。
切分窗口可以分為動態(tài)和靜態(tài)兩種。前者較簡單,本文僅討論后者。創(chuàng)建切分窗口的步驟如下:
(Step 1)、在自己的框架窗口中聲明成員變量,用以對切分窗口進(jìn)行操作。
class CMyFrame : public CMDIChildWnd
{ 。。。 。。。
CSplitterWnd m_Splitter;
CSplitterWnd m_Splitter2;
}
(Step 2)、重載CMDIChildWnd::OnCreateClient函數(shù),創(chuàng)建切分窗口。
BOOL CMyFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
BOOL btn = m_Splitter.CreateStatic(this,1,2);
btn = m_Splitter.CreateView(0,0, RUNTIME_CLASS(CAVIDispView), CSize(100,100), pContext);
m_Splitter2.CreateStatic(&m_Splitter,
2, 1,
WS_CHILD WS_VISIBLE WS_BORDER,
m_Splitter.IdFromRowCol(0, 1));
btn = m_Splitter2.CreateView(0, 0, RUNTIME_CLASS(CBMPView),
CSize(100,100), pContext);
btn = m_Splitter2.CreateView(1, 0, RUNTIME_CLASS(CAVIView),
CSize(100,100), pContext);
return btn;
//return CMDIChildWnd::OnCreateClient(lpcs, pContext);
}
CFrameWnd::OnCreateClient函數(shù)原形為:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CcreateContext * pContext);
缺省的CMDIChildWnd::OnCreateClient函數(shù)根據(jù)pContext參數(shù)提供的信息,調(diào)用CFrameWnd::CreateView函數(shù)創(chuàng)建一個視?梢灾剌d該函數(shù),加載CCreateContext對象中傳遞的值,或改變框架窗口主客戶區(qū)中控制的創(chuàng)建方式。在上面的程序中,筆者 創(chuàng)建了3個切分窗口。比如打開了一個名為“a.avi”的文檔,此時該文檔將有3個視,一個框架窗口。如果執(zhí)行了Window/New操作,則此時有一個文檔,6個視和2個框架窗口。若該文檔調(diào)用CDocument::UpdateAllViews函數(shù),則這6個視的CView::OnUpdate函數(shù)都會被激發(fā)。
(3)、關(guān)于CCreateContext的討論。
CCreateContext是MFC框架所使用的一種結(jié)構(gòu),它將構(gòu)成文檔/視的組件聯(lián)系起來。這個結(jié)構(gòu)包括指向文檔的指針,框架窗口,視以及文檔模板,它還包含一個指向CRuntimeClass的指針,以指明所創(chuàng)建的視的類型。其數(shù)據(jù)成員如下:
m_pNewViewClass:指向創(chuàng)建上下文的視的CRuntimeClass的指針。
m_pCurrentDoc:指向文檔對象的指針,以和新視聯(lián)系起來。
m_pNewDocTemplate:指向與框架窗口的創(chuàng)建相聯(lián)系文檔模板的指針。
m_pLastView:指向已存在的視,它是新產(chǎn)生的視的模型。
m_pCurrentFrame:指向已存在的框架窗口,它是新產(chǎn)生的框架窗口的模型。
程序員可以通過改變CCreateContext對象的值,來創(chuàng)建更加靈活的視。由于過程較復(fù)雜,筆者不再贅許敘,讀者可參閱相關(guān)的Visual C++ Help文檔。
(五)、結(jié)束語
Visual C++ 6.0的文檔/視結(jié)構(gòu)代表了一種新的程序設(shè)計方式,其核心是文檔與視的分離,即數(shù)據(jù)存放與顯示(操作)的分離。在MFC類庫中,各個對象之間的關(guān)系很復(fù)雜,但,只要深入了解后,會發(fā)現(xiàn)它們之間是相互聯(lián)系的,可以相互存取的。如果大家想設(shè)計出靈活、健壯的應(yīng)用程序,就必須深入了解MFC。跟蹤原代碼就是一個較好的方法。文檔/視的關(guān)系的確非常復(fù)雜,如果能知道每個函數(shù)是在哪調(diào)用的,執(zhí)行了何種操作,就能游人刃有余,寫出優(yōu)美的應(yīng)用程序。