MFC獲取文檔、視圖、程序、框架類的指針

當用VC++的Application Wizard生成除了CDialog Basiced以外的應用程序時,將自動產生視圖類、文檔類、主幀窗口類、應用程序類等等。一般來說,程序的核心數據及操作在文檔類中實現。跟界面有關的數據及操作在視圖類中實現。

當需要在某個類中使用不屬於該類的數據時,必須要取得該數據所屬類的指針。從視圖類獲得文檔類的指針是很容易的,用GetDocument即可,這 在一般的MFC文檔中有介紹,也是編程中極爲常用的的操作,比如視圖類在進行重畫等操作時,往往要用到文檔類中的數據。然而只能從視圖類獲得文檔類的指針 是遠遠不夠的,每個類都有獲得其它各個類指針的一套方法,現歸納如下:爲方便說明,現假設已用Application Wizard生成一個SDI應用程序Test,包含如一幾個類:
CTestApp,CTestDoc,CTestView,CMainFrm.

1.從視圖類獲得文檔類的指針

如前所述,在視圖類中需要引用文檔類的地方之前,使用以下語句: 
CTextDoc *pDoc=(CTestDoc*)GetDocument();

以後便可使用pDoc指針訪問文檔類。

此處的強制類型轉換在Test應用程序中並不必需,因爲該程序中只有一個視圖類,並且在Initstance()中用SDI文檔模板進行了裝配,你可以在Test.cpp中的Initstance()方法中看到以下語句:
CSingleDocTemplate *pDocTemplate; 
pDocTemplate=new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CTestDoc),RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CTestView)); 
AddDocTemplate(pDocTemplate); 
以及TestView.h中的線上定義: 
inline CTestDoc* CTestView::GetDocument() 
{ return (CTestDoc*)m_pDocument;}

簡而言之,就是說CTestView的GetDocument()函數自然而然地認爲CTestDoc是與它“相配”的,當生成了一個具有多個視圖 類的應用程序時(如用CSplitterWnd)將窗口分爲兩欄,但這兩欄並非從同一種視圖類派生就屬於這種情況。具體實現在本文討論範圍之外),只有一 個視圖類能與唯一的文檔類用文檔模板進行裝配,那麼在另外一個未經裝配的類中要取得文檔類的指針,則需時行強制類型轉換。

2.從文檔類取得視圖類的指針

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::GetVieww(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."); 
return NULL;} 
return pView;}

其中用了兩次視圖類的成員函數IsKindOf()來判斷,是因爲退出while循環有三種可能:

1.pos爲NULL,即已經不存在下一個視圖類供操作; 
2.pView已符合要求。 
3.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));

4. 從主幀窗口類獲得視圖類指針

對本文所舉的Test這各SDI程序來說,這是簡單的,只需用CFrameWnd類的GetActiveView()成員函數即可。格式如下:
CFrameWnd::GetActiveView()

但將此函數應用在MDI應用的CMDIFrameWnd爲中時,並不象所想的那樣獲得當前活動子窗口的視圖類,而是返回NULL,這是一個要領性問 題。在MDI程序中,CMDIFrameWnd沒有和任何視圖類發生關係,也就是說沒有視圖類直接屬於它,只有子幀窗口類CMDIChildWnd纔是所 有子窗口視圖類的父窗口。而子幀窗口的父窗口才是CFrameWnd。

因此,在MDI程序中獲得活動視圖類的正確方法應爲:先獲得活動子幀窗口,再從活動子幀窗口中獲得活動視圖類:

//獲得活動子幀窗口 
CMDIChildWnd* pChild=(CMDIChildWnd*)GetActiveFrame(); 
//或:CMDIChildWnd* pChild=MDIGetActive(); 
//獲得活動子幀窗口的活動視圖 
CMyView* pView=(CMyView*)pChild->GetActiveView();

5.從視圖類中獲得主幀窗口類指針:

用函數:CWnd::GetParentFrame()或AfxGetMainWnd(); 可達到目的。

GetParentFrame()的工作原理是在父窗口鏈中搜索,直到找到CFrameWnd或其派生類爲止,並返回其指針。用法在InfoViewer中有詳細介紹。

6.在任何類中獲得應用程序類

用MFC全局函數AfxGetApp()可做到。

7.從應用程序類中獲得主幀窗口類

CWinThread類有一個數據成員叫m_pMainWnd,由於CWinApp類由CWinThread派生而來,我們的應用程序爲又由 CWinApp派生而來,所以我們的CTestApp類也有一個m_pMainWnd成員,它所指南的即是CMainFrame類。(需進行合適的強制類 型轉換)。

總結起來有幾點注意: 
A.在類A中獲得類B的指針時,類A應包含類B的頭文件。 
B.在很多時候要進行強制類型轉換,並要注意括號的括法。

由於派生類和父類指針類型的兼容,使明確區分各個類變得十分重要。在拿不準的時候,最好加上強制類型轉換。


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