1.其實Document/View不是什么新東西,Xerox PARC實驗室是這種觀念的濫觴。它是Smalltalk環境中的關鍵性部分,在那里它被稱為Model-View-Controller(MVC)。其中的Model就是MFC的Document,而Controller相當于MFC的Document Template。
2.Document在MFC的CDocument里頭被實例化。CDocument本身并無實際用途,他只是提供一個空殼。你應該從它派生一個自己的類,然后改寫負責文件讀寫操作的Serilize函數。由于CDocument派生自CObject,所以他就有了CObject所支持的一切性質,包括RTTI、動態創建、文件讀寫。又由于它也派生自CCmdTarget,所以它可以接受來自菜單或工具欄的WM_COMMAND消息。
3.View負責呈現Document中的數據。
View在MFC的CView里頭被實例化,同樣應該派生屬于自己的View類,并且在類中改寫專門負責顯示數據的OnDraw函數或OnPRint函數。由于CView派生自CWnd,所以它可以接收一般的Windows消息,又由于它也派生自CCmdTarget,所以它可以接受來自菜單或工具欄的WM_COMMAND消息。
在MFC中,一旦WM_PAINT發生,Framework會自動調用OnDraw函數,View事實上是個沒有邊框的窗口。真正出現時,其外圍還有一個有邊框的窗口,我們稱之為Frame窗口。
4.Document Frame(View Frame)
你可能愿意在使用者操作TEXT數據時,換一套TEXT專用的使用者界面,在使用者操作BITMAP數據時,換一套BITMAP專用的使用者界面。這份工作正式Frame窗口負責。
5.Document Template
每當使用者欲打開一份文件,程序應該做出Document、View、Frame各一份。這三個成為一個運行單元,由所謂的Document Template掌管。MFC有一個CDocTemplate負責此事,他又有兩個派生類,分別是CMultiDocTemplate和CSingleDocTemplate。如果你的程序能夠處理兩中數據類型,你必須制造兩個Document Template,并使用AddDocTemplate函數將他們一一加入系統之中。
6.誰來管理Document Template呢?是CWinApp。來看看InitInstance中應有的相關行為:
CMultiDocTemplate* pDocTemplate;pDocTemplate = new CMultiDocTemplate( IDR_MFCTYPE, RUNTIME_CLASS(CMfcDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CMfcView));AddDocTemplate(pDocTemplate);
Document Template產生Document/View/Frame的行動:
7.當使用者單機File/New命令項,這一命令由CWinApp::OnFileNew接手處理。然后調用CDocManager::OnFileNew->CMultiDocTemplate::OpenDocumentFile.
在OpenDocumentFile中CreateNewDocument動態產生Document,CreateNewFrame動態產生Document Frame。在CreateNewFrame中,不僅Frame被動態創建出來了,其對應窗口也以LoadFrame產生出來了。Document Frame窗口產生之際由于WM_CREATE的產生引發CFrameWnd::OnCreate被喚起。
不僅View對象被動態創建出來了,其對應的實際Windows窗口也以Create函數產生出來。
8.CDocTemplate、CDocument、CView、CFrameWnd 之間的關系
①CWinApp 擁有一個對象指針:CDocManager* m_pDocManager。
②CDocManager 擁有一個指標串行 CPtrList m_templateList, 用來維護一系列的 Document Template。一個程序若支持兩「種」文件型態,就應該有兩份Document Templates,應用程序應該CMyWinApp::InitInstance 中以 AddDocTemplate 將這些 Document Templates 加入由 CDocManager 所維護的鏈表之中。
③CDocTemplate 擁有三個成員變數, 分別持有 Document 、View、Frame 的 CRumtimeClass 指針,另有一個成員變量 m_nIDResource,用來表示此 Document 顯現時應該采用的 UI 對象。這四份數據應該在 CMyWinApp::InitInstance 函數 建構 CDocTemplate(注1)時指定之,成為建構式的參數。當使用者欲打開一 份文件(通常是借著【File/Open】或【File/New】命令項),CDocTemplate 即可借由 Document/View/Frame 之CRuntimeClass 指標(注2)進行動態生成。
注1:在此我們必須有所選擇,要不就使用 CSingleDocTemplate,要不就使用 CMultiDocTemplate , 兩者都是 CDocTemplate 的衍生類別。如果你選用 CSingleDocTemplate,它有一個成員變數 CDocument* m_pOnlyDoc,亦即它一次只能打開一份 Document。如果你選用 CMultiDocTemplate,它有一個成員變數 CPtrList m_docList,表示它能同時打開多個 Documents。
④CDocument 有一個成員變數 CDocTemplate* m_pDocTemplate,回指其Document Template;另有一個成員變量 CPtrList m_viewList,表示它可以同時維護一系列的 Views。
⑤CFrameWnd 有一個成員變量 CView* m_pViewActive, 指向目前正作用中的View。
⑥CView 有一個成員變量 CDocument* m_pDocument,指向相關的 Document。
9.MFC Collection Classes
MFC Collection classes所支持的對象中,有兩種特別需要說明,一是Ob,一是Ptr:
①Ob表示派生自CObject的任何對象。MFC提供CObList、CObArray兩種類。
②Ptr表示對象指針。MFC提供CPtrList、CPtrArray兩種類。
10.Serializable的必要條件
欲讓一個對象有Serialize能力,它必須派生自一個Serializable類。一個類意欲成為Serializable,必須有下列五大條件;
1. 從CObject派生下來。如此一來可保有RTTI、DynamicCreation等機能。
2. 類的聲明部分必須有DECLARE_SERIAL宏。此宏需要一個參數:類名稱。
3. 類的實現部分必須有IMPLEMENT_SERIAL宏。此宏需要三個參數:一是類名稱,三是schema no.。
4. 改寫Serialize虛函數,使它能夠適當地把類的成員變量寫入文件中。
5. 為經類加上一個default構造函數(也就是無參數之構造函數)。這個條件常為人所忽略,但它是必要的,因為若一個對象來自文件,MFC必須先動態創建它,而且在沒有任何參數的情況下調用其構造函數,然后才從文件中讀出對象數據。
一個類若要能夠進行Serializable操作,必須準備Serialize函數,并且在“類別型錄網”中自己的那個CRuntimeClass元素里的schema字段里設置0xFFFF以外的號碼。
11.CArchive類管理文件緩沖區。它是Serialize的對象。CArchive針對許多C++數據類型,windows數據類型以及CObject派生類定義了Operator<<和operator>>重載運算符。
一個C++類如果想要有Serialization機制,就得直接或間接派生自CObject。為的是從CObject派生下列三個運算符:
_AFX_INLINE CArchive &AFXAPI operator<<(CArchive&ar,const CObject*pOb);
_AFX_INLINE CArchive &AFXAPI operator>>(CArchive&ar,CObject*&2pOb);
_AFX_INLINE CArchive &AFXAPI operator>>(CArchive&ar,const CObject*&pOb);
一個類如果希望有Serialization機制,它的第二要件就是使用SERIAL宏。
這個宏包含DYNCRETE宏,并且在類的聲明之中加上:
friend CArchive &AFXAPI operator>>(CArchive&ar,class_name* &pOb);
在類的應用程序文件中加上:
CArchive &AFXAPI operator>>(CArchive&ar,class_name*&pOb) /
{ pOb=(class_name*)ar.ReadObject(RUNTIME_CLASS(class_name)); /
return ar;}
12.當多個視圖顯示同一個文檔,為了保持各個視圖操作的文檔內容的一致性,需要以消息通知使用同一份文檔的其他視圖,CView中有三個虛函數:
1:CView::OnInitialUpdate:負責View的初始化。
2:CView::OnUpdate,當FrameWork調用此函數時,表示Document的內容已經發生了變化。
3:CView::OnDraw:在WM_PAINT消息時會調用此函數,此函數負責更新View窗口的內容。
讓所有的View窗口同步更新數據的關鍵在于兩個函數:
1:CDocument::UpdateAllViews,它會遍歷使用這個文檔的各個視圖,逐個調用它們的OnUpdate函數。
2:CView::OnUpdate,這是個虛函數,可以改寫。它的作用就是告訴View,document的內容已經改變,你需要更新了。
具體步驟為: 1:在CView中調用GetDocument獲得CDocument指針。
2:在CView中調用CDocument::OnUpdateAllViews;
3:所有使用這一份Document的view都被調用OnUpdate。

轉載請標注來源:http://www.blogfshare.com
By:AloneMonkey
新聞熱點
疑難解答