(第四版中文版)[十五]文檔與視圖的分離

 文檔-視圖之間的相互作用函數:

CView::GetDocument() :允許應用程序由視圖得到與之相聯繫的文檔。返回指向文檔的指針,利用它可以對文檔成員函數及公共數據成員進行訪問。

CDocument::GetNextView() :可以用文檔得到視圖,但因爲文檔可以有多個視圖,因而必須對每個視圖調用該成員函數,一般在一循環裏調用。很少使用該函數,因爲應用程序框架提供了更好的方法來循環獲取文檔所有視圖。

當編譯器在視圖類代碼中遇到對GetDocument() 的調用時,它調用的實際上是派生視圖類中的該函數,而不是CView類的中該函數,因此沒有必要將它返回的指針強制轉換爲指向派生文檔類的指針。由於CView::GetDocument() 並不是虛函數,因此下面的語句:

pView->GetDocument(); // CView* pView

調用的是基類中的GetDocument() ,所返回的是指向CDocument對象的指針。

CDocument::UpdateAllView s() :當文檔數據發生變化,所有視圖都必須被通知。如果是在派生文檔類的成員函數中調用該函數,那麼它的第一個參數pSender應爲NULL,如果是在派生視圖類的成員函數中被調用,則應該以如下方式將pSender參數設置爲當前視圖:

GetDocument()->UpdateAllViews(this);

其中的非空參數就使得應用程序框架不再通知當前的視圖,因爲已經假定當前視圖自己進行了更新。該函數還有一些更高級用法。該函數被調用時,具體的視圖被通知參看OnUpdate()。

CView::OnUpdate() :虛函數。當CDocument::UpdateAllViews() 被調用 ,該函數會被調用。該函數要對文檔進行訪問,讀取文檔的數據,然後再對視圖的數據成員或控制進行更新,以便反映出文檔的變化。另外,可以用該函數使視圖的某部分無效以便觸發視圖的OnDraw(),從而進行重繪。該函數默認整個窗口矩形無效。當CDocument::UpdateAllViews() 被調用,pSender參數指向了某個特定的視圖對象,那麼除了該指定視圖,文檔的所有其他視圖的OnUpdate() 都會被調用。

CView::OnInitialUpdate() :該函數除了調用OnUpdate() ,沒有做其它事情。如果要在派生視圖類中重載該函數,就一定要在其中調用基類的該同名函數,或者調用派生類的OnUpdate()。也可以利用派生類的該函數對視圖對象進行初始化。應用程序框架在調用了視圖類的OnCreate()後會立即調用該函數。OnCreate() 只能被調用一次,而該函數可以被調用多次。

CDocument::OnNewDocument() :新建。這個函數是設置文檔數據成員初始值的好地方。AppWizard爲派生文檔類產生了重載的該函數。注意一定要保持對基類函數的調用。

最簡單文檔-視圖程序:

如果不需要文檔有多視圖,只利用應用框架對文件的支持,則可以不使用UpdateAllViews() 和 OnUpdate(),只需按以下步驟創建應用程序:

1、在派生文檔的頭文件(AppWizard產生)中定義文檔的數據成員,主要用來存儲應用程序中的數據。定義成公有類型或者將派生視圖類聲明成文檔類的友元類。

2、在派生視圖類中,對 OnInitialUpdate() 虛成員函數進行重載。該函數應該對視圖進行更新,以便反映出當前的文檔數據。

3、在派生視圖類中,讓窗口消息控制函數和命令消息控制函數直接讀取和更新文檔數據成員,利用 GetDocument()對文檔對象進行訪問。

下面是在這一簡單文檔-視圖環境事件發生的次序:

應用程序啓動           CMyDocument對象被創建

                 CMyView對象被創建

                 視圖窗口被創建

                 CMyView::OnCreate() 被調用(如果被映射的話)

                 CMyDocument::OnNewDocument() 被調用

                 CMyView::OnInitialUpdate() 被調用

                 視圖對象被初始化

                 視圖窗口無效

                 CMyView::OnDraw() 被調用

用戶編輯數據           CMyView 函數對 CMyDocument 數據成員進行更新

用戶退出應用程序         CMyView 對象被刪除

                 CMyDocument 對象被刪除/

CFormView 類:

具有無模式對話框的許多特點。如果用AppWizard產生一個FormView對話框,則無需設置。如果用對話框編輯器創建對話框,必須在屬性裏設置:Sytle=Child ,  Border=None,   Visible=unchecked 。

CFormView 對象可接收直接來自它的控制的通知消息,也可接收來自應用程序框架的命令消息。明顯區別於CDialog,同時也使得框架的主菜單或工具欄中對視圖進行控制變得較爲容易。

CFormView是從CView (確切是CScrollView)派生而來,不是從CDialog派生的。因此不能假設它可支持所有的CDialog成員函數,CFormView類並不包含OnInitDialog()、OnOK()、OnCancel() 虛函數,也不調用UpdateData() 和DDX函數,必須在適當的時候,通常是對控制通知消息或命令消息進行響應時,自己調用這些函數。CFormView可以使用許多CDialog類的成員函數,只須將其強制轉換爲 CDialog指針即可。

高級文檔-視圖的相互作用:

多視圖應用程序的主要問題在於:如果對視圖#1進行編輯,那麼視圖#2也要隨之更新,以便反映出文檔的變化,則此時就需要用到 UpdateAllViews() 和 OnUpdate() 。多視圖應用程序具體開發步驟如下:

1、在派生文檔類的頭文件(由AppWizard產生)中定義文檔的數據成員。如果需要,還可以將這些數據成員定義成私有的,並且定義一些成員函數對它們進行訪問,或者將視圖類聲明成文檔類的友元。

2、在派生視圖類中,使用ClassWizard重載OnUpdate() 虛成員函數。

3、對所有的命令消息作出判斷,判斷哪些是針對文檔的,哪些是針對視圖的。然後將命令映射到相應的類。

4、在派生視圖類中,允許相應的命令消息控制函數對文檔數據進行更新。在它們退出之前,一定要調用CDocument::UpdateAllViews()。可以用CView::GetDocument成員函數的類型安全版本來訪問視圖的文檔。

5、在派生文檔類中,允許相應的命令消息控制函數對文檔數據進行更新。在它們退出前,一定要調用CDocument::UpdateAllViews()。

下面是複雜的文檔-視圖之間的相互作用過程中事件發生的次序:

應用程序啓動            CMyDocument對象被創建

                  CMyView 對象被創建

                  其他視圖對象被創建

                  視圖窗口被創建

                  CMyView::OnCreate() 被調用(如果被映射)

                                          CDocument::OnNewDocument() 被調用

                  CView::OnInitialUpdate() 被調用

                   調用CMyView::OnUpdate

                   初始化視圖

用戶執行視圖命令           CMyView函數更新CMyDocument 的數據成員

                               調用 CDocument::UpdateAllViews

                   其他視圖的OnUpdate() 被調用

用戶執行文檔命令                                     CMyDocument函數對數據成員進行更新

                             調用CDocument::UpdateAllViews

                             CMyView::OnUpdate() 被調用

                 其他視圖的OnUpdate() 被調用

用戶退出應用程序         視圖對象被刪除

                 CMyDocument對象被刪除

CDocument::DeleteContents() :

刪除文檔內容。文檔被關閉時,應用程序框架會自動調用重載的 DeleteContents(),在其它一些情況下,該函數也會被調用。

CObList 類:

能夠支持指向 CObject 派生類對象的指針列表。CPtrList 則保存的是 void 指針,而不是 CObject 指針。CObList另一個很重要的特性是可以包含混合的指針。

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