<深入淺出mfc>第8章Document-View 深入探討

第8章Document-View 深入探討

代碼的位置在點擊這下載:http://download.csdn.net/detail/caidaoqq/6951265

1.   CDocTemplate管理CDocument / CView / CframeWnd


圖8-2 解釋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)進行動態生成。

■ CDocument 有一個成員變量CDocTemplate* m_pDocTemplate,回指其Document

Template;另有一個成員變量CPtrList m_viewList,表示它可以同時維護一系列

的Views。

■ CFrameWnd 有一個成員變量CView* m_pViewActive ,指向目前正作用中的

View 。

■ CView 有一個成員變量CDocument* m_pDocument,指向相關的Document。

 

2.   Scribble Step1 的Document---數據結構設計

MFC Collection Classes。它們分爲三種類型,用來管理一大羣對象:

■ Array:數組,有次序性(需依序處理),可動態增減大小,索引值爲整數。

■ List:雙向串行,有次序性(需依序處理),無索引。串行有頭尾,可從頭尾

或從串行的任何位置安插元素,速度極快。

■ Map:又稱爲Dictionary,其內對象成對存在,一爲鍵值對象(key object),

一爲實值對象(value object)。

 

CPenPaintTestDoc的成員變量:

■  m_strokeList:這是一個CObList 對象,代表一個串行。串行中的元素是什麼型

態?答案是CObject*。但實際運作時,我們可以把基礎類別之指針指向衍生類

別之對象。現在我們想讓這個串行成爲「由CStroke對象構成的串行」,因此顯然CStroke

必須衍生自

CObject 才行,而事實上它的確是。

■  m_nPenWidth:每一線條都有自己的筆寬,而目前使用的筆寬記錄於此。

■  m_penCur:這是一個CPen 對象。程序依據上述的筆寬,配置一支筆,準備用

來畫線條。筆寬可以指定。注意,筆寬的設定對象是線條,不是單一的點,也不是一整張圖。

 

CPenPaintTestDoc的成員函數:

■ OnNewDocument、OnOpenDocument、InitDocument。產生Document 的時機有二,

一是使用者選按【File/New】,一是使用者選按【File/Open】。當這兩種情況

發生,Application Framework會分別調用Document 類別的OnNewDocument

OnOpenDocument。

■  NewStroke。這個函數將產生一個新的CStroke對象,並把它加到串行之中

結果:產生了一個新線條,設定了線條寬度,並將新線條加入串行尾端

■  DeleteContent。利用CObList::RemoveHead把串行的最前端元素拿掉。

■  Serialize。這個函數負責文件讀寫。由於文件掌管線條串行,線條串行又掌管

各線條

 

CStroke的成員變量

■  m_pointArray:這是一個CArray 對象,用以記錄一系列的CPoint 對象,這些

CPoint 對象由鼠標座標轉化而來。

■  m_nPenWidth:一個整數,代表線條寬度。雖然ScribbleStep1 的線條寬度是

固定的。

 

CStroke的成員函數

■  DrawStroke :繪圖原本是View 的責任,爲什麼卻在CStroke 中有一個

DrawStroke?因爲線條的內容只有CStroke 自己知道,當然由CStroke 的成

員函數把它畫出來最是理想。這麼一來,View 就可以一一調用線條自己的繪

圖函數,很輕鬆。

■  Serialize:讓我們這麼想象寫檔動作:使用者下命令給程序,程序發命令給文

件,文件發命令給線條,線條發命令給點數組,點數組於是把一個個的座標點

寫入磁盤中。

3.   Scribble Step1 的View:資料重繪與編輯

View 有兩個最重要的任務,一是負責資料的顯示,另一是負責資料的編輯

 

本例的CPenPaintTestView包括以下特質:

■„解讀CPenPaintTestDoc中的資料,包括筆寬以及一系列的CPoint 對象,畫在View

窗口上。

■  允許使用者以鼠標左鍵充當畫筆在View 窗口內塗抹,換句話說CPenPaintTestView

必須接受並處理WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP

三個消息。

 

View 的重繪動作:GetDocument 和OnDraw

以下是CPenPaintTestView中與重繪動作有關的成員變量和成員函數。

 

CPenPaintTestView的成員變量

     m_pStrokeCur:一個指針,指向目前正在工作的線條。

■  m_ptPrev:線條中的前一個工作點。我們將在這個點與目前鼠標按下的點之間

畫一條直線。雖說理想情況下鼠標軌跡的每一個點都應該被記錄下來,但如果

鼠標移動太快來不及記錄,只好在兩點之間拉直線。

 

CPenPaintTestView的成員函數

■   OnDraw:這是一個虛擬函數,負責將Document的數據顯示出來。改寫它是程

式員最大的責任之一。

■   GetDocument:AppWizard爲我們做出這樣的碼

■   OnPreparePrinting,OnBeginPrinting,OnEndPrinting:這三個CView 虛擬函數將

用來改善打印行爲。

 

Serialize:對象的文件讀寫

對象必須能夠永續生存,也就是它們必須能夠在程序結束時儲存到文件中,並且在程序重新激活時再恢復回來。儲存和恢復對象的過程在MFC 之中就稱爲serialization。負責這件重要任務的,是MFC CObject 類別中一個名爲Serialize的虛擬函數,文件的「讀」「寫」動作均透過它。

Scribble程序的文件讀寫動作是這麼分工的:

■ Framework 調用CPenPaintTestDoc::Serialize,用以對付文件。

CPenPaintTestDoc再往下調用CStroke::Serialize,用以對付線條。

■ CStroke 再往下調用CArray::Serialize,用以對付點數組。

 

Serializable的必要條件:

1. 從CObject 衍生下來。如此一來可保有RTTI、Dynamic Creation 等機能。

2. 類別的聲明部份必須有DECLARE_SERIAL 宏。此宏需要一個參數:類別

名稱。

3. 類別的實作部份必須有IMPLEMENT_SERIAL 宏。此宏需要三個參數:

一是類別名稱,二是父類別名稱,三是schemano.。

4. 改寫Serialize 虛擬函數,使它能夠適當地把類別的成員變量寫入文件中。

5. 爲此類別加上一個default 構造式(也就是無參數之構造式)。這個條件常爲

人所忽略,但它是必要的,因爲若一個對象來自文件,MFC必須先動態生成

它,而且在沒有任何參數的情況下調用其構造式,然後才從文件中讀出對象資

料。

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