文檔、視圖、架構視窗、文件範本之間的相互關係

來源:互聯網
上載者:User

轉自:http://blog.sina.com.cn/s/blog_4d8205e40100gjfe.html

要瞭解文檔、視圖、架構視窗、文件範本之間的相互關係,關鍵要理解他們的結構  
1、首先應該對CWinApp類有充分的瞭解  
它包含並管理著應用程式的文檔/視窗的所有資訊。
它有一個成員變數CDocManager   *m_pDocManager,此變數是文檔/視窗的管理器。
m_templateList是CDocManager裡的一個列表,此列表裡儲存了所有文件範本的指標。
當使用者調用
CWinApp::AddDocTemplate(pDocTemplate)後,該pDocTemplate存入了CWinApp::m_pDocManager::m_templateList裡。  
CWinApp::GetFirstDocTemplatePosition()  
CWinApp::GetNextDocTemplate(POSITION&   pos)  
是遍例所有的文件範本指標。  
2、上面我們提到了文件範本(CMultiDocTemplate(我們主要針對文檔)),  
這是一個極重要的類。
CMultiDocTemplate::m_docList儲存的所有該種文檔的文檔執行個體的指標列表。
下面兩個函數用於維護CMultiDocTemplate::m_docList資料  
CMultiDocTemplate::AddDocument(CDocument*   pDoc);  
CMultiDocTemplate::RemoveDocument(CDocument*   pDoc);  
而  
CMultiDocTemplate::GetFirstDocPosition()   const;  
CMultiDocTemplate::CDocument*   GetNextDoc(POSITION&   rPos)   const;  
用於遍例該文件類型所有文檔執行個體。  
3、上面提到文檔(CDocument)  
CDocument我們最熟悉不過了。每一個文檔執行個體可有多個視與之相對應。  
CDocument::m_viewList用來儲存所有與此文檔執行個體相關的View  
CDocument::GetDocTemplate可獲得CMultiDocTemplate;  
4、CView
他是放在CMDIChildWnd裡的,每一個CMDIChildWnd有一個View  
CView::GetDocument可獲得與此視相關的CDocument  
CView::GetParentFrame()可獲得CMDIChildWnd;

總結
通過以上分析可見CWinApp,CMDIChildWnd,CView,CDocument,CMultiDocTemplate之間知道其中一個執行個體必可知道其他所有幾個執行個體,CWinApp統領全域,任何時候,只要獲得CWinApp執行個體,則所有的文件範本,文檔執行個體,視,Frame視窗均可被枚舉出來。AfxGetApp()獲得CWinApp執行個體指標。

***************************************************************************************************************

1) 在View中獲得Doc指標
2) 在App中獲得MainFrame指標
3) 在View中獲得MainFrame指標
4) 獲得View(已建立)指標
5) 獲得當前文檔指標
6) 獲得狀態列與工具列指標
7) 獲得狀態列與工具列變數
8) 在Mainframe獲得菜單指標
9) 在任何類中獲得應用程式類
10) 從文檔類取得視圖類的指標(1)
11) 在App中獲得文件範本指標
12) 從文件範本獲得文檔類指標
13) 在文檔類中獲得文件範本指標
14) 從文檔類取得視圖類的指標(2)
15) 從一個視圖類取得另一視圖類的指標
VC中編程對於剛剛開始學習的同學,最大的障礙和問題就是訊息機制和指標擷取與操作。其實這些內容基本上是每本VC學習工具書上必講的內容,而且通過MSDN很多問題都能解決。下面文字主要是個人在編程中指標使用的一些體會,說的不當的地方請指正。
一般我們使用的架構是VC提供的Wizard產生的MFC App Wizard(exe)架構,無論是多文檔還是單文檔,都存在指標擷取和操作問題。下面這節內容主要是一般的架構,然後再講多線程中的指標使用。使用到的類需要包含響應的標頭檔。首先一般獲得本類(視,文檔,對話方塊都支援)執行個體指標this,用this的目的,主要可以通過類中的函數向其他類或者函數中髮指針,以便於在非本類中操作和使用本類中的功能。

1) 在View中獲得Doc指標
CYouSDIDoc *pDoc=GetDocument();一個視只能有一個文檔。

2) 在App中獲得MainFrame指標
CWinApp中的m_pMainWnd變數就是MainFrame的指標
也可以: CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();

3) 在View中獲得MainFrame指標
CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;

4) 獲得View(已建立)指標
CyouView *pView=(CyouView *)pMain->GetActiveView();

5) 獲得當前文檔指標
CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd->GetActiveDocument();

6) 獲得狀態列與工具列指標
CStatusBar * pStatusBar=(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);
CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);

7) 如果架構中加入工具列和狀態列變數還可以這樣
(CMainFrame *)GetParent()->m_wndToolBar;
(CMainFrame *)GetParent()->m_wndStatusBar;

8) 在Mainframe獲得菜單指標 CMenu *pMenu=m_pMainWnd->GetMenu();

9) 在任何類中獲得應用程式類
用MFC全域函數AfxGetApp()獲得。

10) 從文檔類取得視圖類的指標
我是從http://download.cqcnc.com/soft/program/article/vc/vc405.html學到的。
從文檔獲得視圖類指標目的一般為了控制同一文檔的多個視圖的定位問題,我的體會特別是文文書處理CEditView當產生多個視圖類時,這個功能是非常需要的。
CDocument類提供了兩個函數用於視圖類的定位:
GetFirstViewPosition()和GetNextView()
virtual POSITION GetFirstViewPosition() const;
virtual CView* GetNextView(POSITION& rPosition) const;
注意:GetNextView()括弧中的參數用的是引用方式,因此執行後值可能改變。
GetFirstViewPosition()用於返回第一個視圖位置(返回的並非視圖類指標,而是一個POSITION類型值),GetNextView()有兩個功能:返回下一個視圖類的指標以及用引用調用的方式來改變傳入的POSITION型別參數的值。很明顯,在Test程式中,只有一個視圖類,因此只需將這兩個函數調用一次即可得到CTestView的指標如下(需定義一個POSITION結構變數來輔助操作):
CTestView* pTestView;
POSITION pos=GetFirstViewPosition();
pTestView=GetNextView(pos);
這樣,便可到了CTestView類的指標pTestView.執行完幾句後,變數pos=NULL,因為沒有下一個視圖類,自然也沒有下一個視圖類的POSITION.但是這幾條語句太簡單,不具有太強的通用性和安全特徵;當象前面說的那樣,當要在多個視圖為中返回某個指定類的指標時,我們需要遍曆所有視圖類,直到找到指定類為止。判斷一個類指標指向的是否某個類的執行個體時,可用IsKindOf()成員函數時行檢查,如:
pView->IsKindOf(RUNTIME_CLASS(CTestView));
即可檢查pView所指是否是CTestView類。
有了以上基礎,我們已經可以從文檔類取得任何類的指標。為了方便,我們將其作為一個文檔類的成員函數,它有一個參數,表示要獲得哪個類的指標。實現如下:
CView* CTestDoc::GetView(CRuntimeClass* pClass)
{
CView* pView;
POSITION pos=GetFirstViewPosition();
while(pos!=NULL){
pView=GetNextView(pos);
if(!pView->IsKindOf(pClass))
break;
}
if(!pView->IsKindOf(pClass)){
AfxMessageBox("Connt Locate the View.\r\n http://www.VCKBASE.com");
return NULL;
}
return pView;
}
其中用了兩次視圖類的成員函數IsKindOf()來判斷,是因為退出while迴圈有三種
可能:
1.pos為NULL,即已經不存在下一個視圖類供操作;
2.pView已符合要求。
1和2同是滿足。這是因為GetNextView()的功能是將當前視圖指標改變成一個視圖的位置同時返回當前視圖指標,因此pos是pView的下一個視圖類的POSITION,完全有可能既是pos==NULL又是pView符合需要。當所需的視圖是最後一個視圖是最後一個視圖類時就如引。因此需採用兩次判斷。
使用該函數應遵循如下格式(以取得CTestView指標為例):
CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));
RUNTIME_CLASS是一個宏,可以簡單地理解它的作用:將類的名字轉化為CRuntimeClass為指標。至於強制類型轉換也是為了安全特性考慮的,因為從同一個基類之間的指標類型是互相相容的。這種強制類型轉換也許並不必要,但能避免一些可能出現的麻煩。
3.從一個視圖類取得另一視圖類的指標
綜合1和2,很容易得出視圖類之間互相獲得指標的方法:就是用文檔類作中轉,先用1的方法得到文檔類的指標,再用2的方法,以文檔類的視圖定位函數取得另一個視圖類。同樣,可以實現成一個函數:
(假設要從CTestAView中取得指向其它視圖類的指標)
CView* CTestAView::GetView(CRuntimeClass* pClass)
{
CTestDoc* pDoc=(CTestDoc*)GetDocument();
CView* pView;
POSITION pos=pDoc->GetFirstViewPosition();
while(pos!=NULL){
pView=pDoc->GetNextView(pos);
if(!pView->IsKindOf(pClass))
break;
}
if(!pView->IsKindOf(pClass)){
AfxMessageBox("Connt Locate the View.");
return NULL;
}
return pView;
}
這個函數和2中的GetView()相比,一是多了第一句以取得文檔類指標,二是在GetFirstViewPosition()和GetNextView()前加上了文檔類指標,以表示它們是文檔類成員函數。有了此函數;當要從CTestAView中取得CTestBView的指標時,只需如下:
CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));

11)對於單文檔中也可以加入多個文件範本,但是一般的開發就使用MDI方式開發多文件範本,其方法與上述視圖的擷取方法很接近,這裡稍做解釋,如果不清楚,
請查閱MSDN,(以下四個內容(11、12、13、14)來源:http://sanjianxia.myrice.com/vc/vc45.htm)
可以用CWinApp::GetFirstDocTemplatePostion獲得應用程式註冊的第一個文件範本的位置;利用該值來調用CWinApp::GetNextDocTemplate函數,獲得第一個CDocTemplate對象指標。
POSITION GetFirstDocTemplate( ) const;
CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;
第二個函數返回由pos 標識的文件範本。POSITION是MFC定義的一個用於迭代或對象指標檢索的值。通過這兩個函數,應用程式可以遍曆整個文件範本列表。如果被檢索
的文件範本是模板列表中的最後一個,則pos參數被置為NULL。

12)一個文件範本可以有多個文檔,每個文件範本都保留並維護了一個所有對應文檔的指標列表。
用CDocTemplate::GetFirstDocPosition函數獲得與文件範本相關的文檔集合中第一個文檔的位置,並用POSITION值作為CDocTemplate::GetNextDoc的參數來重複遍曆與模板相關的文檔列表。函數原形為:
viaual POSITION GetFirstDocPosition( ) const = 0;
visual CDocument *GetNextDoc(POSITION & rPos) const = 0;
如果列表為空白,則rPos被置為NULL.

13)在文檔中可以調用CDocument::GetDocTemplate獲得指向該文件範本的指標。
函數原形如下:
CDocTemplate * GetDocTemplate ( ) const;
如果該文檔不屬於文件範本管理,則傳回值為NULL。

14)一個文檔可以有多個視。每一個文檔都保留並維護一個所有相關視的列表。
CDocument::AddView將一個視串連到文檔上,將該視加入到文檔相聯絡的視的列表中,並將視的文檔指標指向該文檔。
當有File/New、File/Open、Windows/New或Window/Split的命令而將一個新建立的視的對象串連到文檔上時, MFC會自動調用該函數,架構通過文檔/視的結構將文檔和視聯絡起來。當然,程式員也可以根據自己的需要調用該函數。
Virtual POSITION GetFirstViewPosition( ) const;
Virtual CView * GetNextView( POSITION &rPosition) cosnt;
應用程式可以調用CDocument::GetFirstViewPosition返回與調用文檔相聯絡的視的列表中的第一個視的位置,並調用CDocument::GetNextView返回指定位置的視,並將
rPositon的值置為列表中下一個視的POSITION值。如果找到的視為列表中的最後一個視,則將rPosition置為NULL.

15)從一個視圖類取得另一視圖類的指標
這個應用在多視的應用程式中很多見,一般如果自己在主程式或者主架構中做好變數記號,也可以獲得,還有比較通用的就是用文檔類作中轉,以文檔類的視圖遍曆定位,取得另一個視圖類。這個功能從本文第10項中可以得到。 
————————————————————————————————————————————

--------------------------------------------------------------------------------

VC多文檔程式結構[轉]
2008-04-03 15:03
1、模板、文檔、視圖、架構的關係

連載1~5我們各個擊破地講解了文檔、文件範本、視圖和架構類,連載1已經強調這些類有著親密的內部聯絡,總結 1~5我們可以概括其聯絡為:

(1)文檔保留該文檔的視圖列表和指向建立該文檔的文件範本的指標;文檔至少有一個相關聯的視圖,而視圖只能與一個文檔相關聯。

(2)視圖保留指向其文檔的指標,並被包含在其父架構視窗中;

(3)文檔架構視窗(即包含視圖的mdi子視窗)保留指向其當前即時檢視的指標;

(4)文件範本保留其已開啟文檔的列表,維護架構視窗、文檔及視圖的映射;

(5)應用程式保留其文件範本的列表。

我們可以通過一組函數讓這些類之間相互可訪問,表6-1給出這些函數。

表6-1 文檔、文件範本、視圖和架構類的互相訪問

--------------------------------------------------------------------------------
調用全域函數afxgetapp可以得到cwinapp應用類指標
應用afxgetapp()->m_pmainwnd為架構視窗指標;
用cwinapp::getfirstdoctemplatepostion、cwinapp::getnextdoctemplate來遍曆所有文件範本文檔
調用cdocument::getfirstviewposition,cdocument::getnextview來遍曆所有和文檔關聯的視圖;
調用cdocument:: getdoctemplate 擷取文件範本指標文件範本
調用cdoctemplate::getfirstdocposition、cdoctemplate::getnextdoc來遍曆所有對應文檔視圖
調用cview::getdocument 得到對應的文檔指標;
調用cview::getparentframe 擷取架構視窗文檔架構視窗
調用cframewnd::getactiveview 擷取當前得到當前即時檢視指標;
調用cframewnd::getactivedocument 擷取附加到當前視圖的文檔指標
mdi架構視窗調用cmdiframewnd::mdigetactive 擷取當前活動的mdi子視窗(cmdichildwnd)

我們列舉一個例子,綜合應用上表中的函數,寫一段代碼,它完成遍曆文件範本、文檔和視圖的功能:

cmyapp *pmyapp = (cmyapp*)afxgetapp();  //得到應用程式指標
position p = pmyapp->getfirstdoctemplateposition(); //得到第1個文件範本
while (p != null)  //遍曆文件範本
{
cdoctemplate *pdoctemplate = pmyapp->getnextdoctemplate(p);
position p1 = pdoctemplate->getfirstdocposition(); //得到文件範本對應的第1個文檔
while (p1 != null)  //遍曆文件範本對應的文檔
{
cdocument *pdocument = pdoctemplate->getnextdoc(p1);
position p2 = pdocument->getfirstviewposition();  //得到文檔對應的第1個視圖
while (p2 != null)  //遍曆文檔對應的視圖
{
cview *pview = pdocument->getnextview(p2);
}
}
}
由此可見,下面的管理關聯性和實現途徑都是完全類似的:

(1)應用程式之於文件範本;

(2)文件範本之於文檔;

(3)文檔之於視圖。

×××××××××××××××××××××××××××××××××××××××××

1、應用程式物件有一個文件範本管理器CDocManager* m_pDocManager(第一次調用AddDocTemplate時new出來)

2、文件範本管理器有一個文件範本對象列表CPtrList m_templateList(AddDocTemplate 函數負責添加該列表)

3、文件範本對象擁有文檔、視圖、架構的靜態CRuntimeClass成員指標用於動態建立,還有一個 m_nIDResource用來表示應採用的UI對象

4、每個文件範本對象擁有 m_pOnlyDoc 或 m_docList (文檔指標或文檔指標列表),OnFileNew 和 OnFileOpen都調用文件範本對象的OpenDocumentFile,OpenDocumentFile 調用文件範本的 CreateNewDocument,CreateNewDocument再調用文件範本的 AddDocument 填充該文檔列表或文檔指標

5、文檔對象有一個文件範本指標 m_pDocTemplate (回指文檔對象所屬模板對象).同上,也是文件範本的 AddDocument 成員函數把 this 指標(文件範本自身).塞給剛剛建立的文檔對象

6、文檔對象有一個 m_viewList(視圖列表),OnFileNew 和 OnFileOpen 都調用文件範本對象的OpenDocumentFile,該函數調用 CreateNewDocument 建立文檔,然後調用 CreateNewFrame 建立架構對象.

CreateNewFrame 構造CCreateContext對象
CCreateContext兩個重要欄位:(1)剛建立的文檔指標(2)視圖的CRuntimeClass指標
CreateNewFrame 建立架構對象後由該對象調用 LoadFrame
LoadFrame 的最後一個參數即為 CCreateContext 指標

LoadFrame 調用 Create,Create 再調用 CreateEx 最後一個參數均為此CCreateContext指標
Create的調用由訊息映射表引發CFrameWnd::OnCreate被調用
OnCreate的LPCREATESTRUCT的一個欄位lpCreateParams 仍然是這個CCreateContext指標

則在CFrame::OnCreate中,由這個CCreateContext的CRuntimeClass(視圖的)來調用 CreateObject
產生視圖對象後,由該對象調用Create(最後一個參數仍然是這個CCreateContext指標)

視圖對象的Create由訊息映射表引發視圖對象的OnCreate被調用
視圖的OnCreate的參數 LPCREATESTRUCT 的 lpCreateParams 還是這個CCreateContext指標)
於是利用 CCreateContext 的成員 m_pCurrentDoc (當前文檔)
來調用 CDocument::AddView 把視圖加入文檔的視圖列表

7、視圖有一個文檔指標m_pDocument (指向所屬文檔)
同上,也是CDocument::AddView函數初始化的,如下所示:
pView->m_pDocument = this;

8、架構有一個m_pViewActive(即時檢視)
由架構的SetActiveView進行設定

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.