作者:疙瘩
當(dāng)用VC++的Application Wizard生成除了CDialog Basiced以外的應(yīng)用程序時,將自動產(chǎn)生視圖類、文檔類、主幀窗口類、應(yīng)用程序類等等。一般來說,程序的核心數(shù)據(jù)及操作在文檔類中實(shí)現(xiàn)。跟界面有關(guān)的數(shù)據(jù)及操作在視圖類中實(shí)現(xiàn)。當(dāng)需要在某個類中使用不屬于該類的數(shù)據(jù)時,必須要取得該數(shù)據(jù)所屬類的指針。從視圖類獲得文檔類的指針是很容易的,用GetDocument即可,這在一般的MFC文檔中有介紹,也是編程中極為常用的的操作,比如視圖類在進(jìn)行重畫等操作時,往往要用到文檔類中的數(shù)據(jù)。然而只能從視圖類獲得文檔類的指針是遠(yuǎn)遠(yuǎn)不夠的,每個類都有獲得其它各個類指針的一套方法,現(xiàn)歸納如下: 為方便說明,現(xiàn)假設(shè)已用Application Wizard生成一個SDI應(yīng)用程序Test,包含如一幾個類:
CTestApp,CTestDoc,CTestView,CMainFrm.1.從視圖類獲得文檔類的指針 如前所述,在視圖類中需要引用文檔類的地方之前,使用以下語句: CTextDoc *pDoc=(CTestDoc*)GetDocument(); 以后便可使用pDoc指針訪問文檔類。 此處的強(qiáng)制類型轉(zhuǎn)換在Test應(yīng)用程序中并不必需,因?yàn)樵摮绦蛑兄挥幸粋視圖類,并且在Initstance()中用SDI文檔模板進(jìn)行了裝配,你可以在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()函數(shù)自然而然地認(rèn)為CTestDoc是與它“相配”的,當(dāng)生成了一個具有多個視圖類的應(yīng)用程序時(如用CSplitterWnd)將窗口分為兩欄,但這兩欄并非從同一種視圖類派生就屬于這種情況。具體實(shí)現(xiàn)在本文討論范圍之外),只有一個視圖類能與唯一的文檔類用文檔模板進(jìn)行裝配,那么在另外一個未經(jīng)裝配的類中要取得文檔類的指針,則需時行強(qiáng)制類型轉(zhuǎn)換。2.從文檔類取得視圖類的指針 CDocument類提供了兩個函數(shù)用于視圖類的定位:GetFirstViewPosition()和GetNextView(),具體語法如下: virtual POSITION GetFirstViewPosition() const; virtual CView* GetNextView(POSITION& rPosition) const; 注意:GetNextView()括號中的參數(shù)用的是引用方式,因此執(zhí)行后值可能改變。 GetFirstViewPosition()用于返回第一個視圖位置(返回的并非視圖類指針,而是一個POSITION類型值),GetNextView()有兩個功能:返回下一個視圖類的指針以及用引用調(diào)動的方式來改變傳入的POSITION類型參數(shù)的值。很明顯,在Test程序中,只有一個視圖類,因此只需將這兩個函數(shù)調(diào)用一次即可得到CTestView的指針如下(需定義一個POSITION結(jié)構(gòu)變量來輔助操作): CTestView* pTestView; POSITION pos=GetFirstViewPosition(); pTestView=GetNextView(pos); 這樣,便可到了CTestView類的指針pTestView.執(zhí)行完成幾句后,變量pos=NULL,因?yàn)闆]有下一個視圖類,自然也沒有下一個視圖類的POSITION.但是之幾條語句太簡單,不具有太強(qiáng)的通用性和安全特征;當(dāng)象前面說的那樣,當(dāng)要在多個視圖為中返回某個指定類的指針時,我們需要遍歷所有視圖類,直到找到指定類為止。判斷一個類指針指向的是否某個類的實(shí)例時,可用IsKindOf()成員函數(shù)時行檢查,如: pView->IsKindOf(RUNTIME_CLASS(CTestView)); 即可檢查pView所指是否是CTestView類。 有了以上基礎(chǔ),我們已經(jīng)可以從文檔類取得任何類的指針。為了方便,我們將其作為一個文檔類的成員函數(shù),它有一個參數(shù),表示要獲得哪個類的指針。實(shí)現(xiàn)如下: 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;} 其中用了兩次視圖類的成員函數(shù)IsKindOf()來判斷,是因?yàn)橥顺鰓hile循環(huán)有三種可能: 1.pos為NULL,即已經(jīng)不存在下一個視圖類供操作; 2.pView已符合要求。 3.1和2同是滿足。這是因?yàn)镚etNextView()的功能是將當(dāng)前視圖指針改變成一個視圖的位置同時返回當(dāng)前視圖指針,因此pos是pView的下一個視圖類的POSITION,完全有可能既是pos==NULL又是pView符合需要。當(dāng)所需的視圖是最后一個視圖是最后一個視圖類時就如引。因此需采用兩次判斷。 使用該函數(shù)應(yīng)遵循如下格式(以取得CTestView指針為例): CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView)); RUNTIME_CLASS是一個宏,可以簡單地理解它的作用:將類的名字轉(zhuǎn)化為CRuntimeClass為指針。 至于強(qiáng)制類型轉(zhuǎn)換也是為了安全特性考慮的,因?yàn)閺耐粋基類之間的指針類型是互相兼容的。這種強(qiáng)制類型轉(zhuǎn)換也許并不必要,但能避免一些可能出現(xiàn)的麻煩。3.從一個視圖類取得另一視圖類的指針 綜合1和2,很容易得出視圖類之間互相獲得指針的方法:就是用文檔類作中轉(zhuǎn),先用1的方法得到文檔類的指針,再用2的方法,以文檔類的視圖定位函數(shù)取得另一個視圖類。同樣,可以實(shí)現(xiàn)成一個函數(shù): (假設(shè)要從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;} 這個函數(shù)和2中的GetView()相比,一是多了第一句以取得文檔類指針,二是在GetFirstViewPosition()和GetNextView()前加上了文檔類指針,以表示它們是文檔類成員函數(shù)。 有了此函數(shù);當(dāng)要從CTestAView中取得CTestBView的指針時,只需如下: CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));4. 從主幀窗口類獲得視圖類指針 對本文所舉的Test這各SDI程序來說,這是簡單的,只需用CFrameWnd類的GetActiveView()成員函數(shù)即可。格式如下: CFrameWnd::GetActiveView() 但將此函數(shù)應(yīng)用在MDI應(yīng)用的CMDIFrameWnd為中時,并不象所想的那樣獲得當(dāng)前活動子窗口的視圖類,而是返回NULL,這是一個要領(lǐng)性問題。在MDI程序中,CMDIFrameWnd沒有和任何視圖類發(fā)生關(guān)系,也就是說沒有視圖類直接屬于它,只有子幀窗口類CMDIChildWnd才是所有子窗口視圖類的父窗口。而子幀窗口的父窗口才是CFrameWnd。因此,在MDI程序中獲得活動視圖類的正確方法應(yīng)為:先獲得活動子幀窗口,再從活動子幀窗口中獲得活動視圖類: //獲得活動子幀窗口 CMDIChildWnd* pChild=(CMDIChildWnd*)GetActiveFrame(); //或:CMDIChildWnd* pChild=MDIGetActive(); //獲得活動子幀窗口的活動視圖 CMyView* pView=(CMyView*)pChild->GetActiveView();5.從視圖類中獲得主幀窗口類指針:用函數(shù):CWnd::GetParentFrame()或AfxGetMainWnd(); 可達(dá)到目的。GetParentFrame()的工作原理是在父窗口鏈中搜索,直到找到CFrameWnd或其派生類為止,并返回其指針。用法在InfoViewer中有詳細(xì)介紹。6.在任何類中獲得應(yīng)用程序類 用MFC全局函數(shù)AfxGetApp()可做到。7.從應(yīng)用程序類中獲得主幀窗口類 CWinThread類有一個數(shù)據(jù)成員叫m_pMainWnd,由于CWinApp類由CWinThread派生而來,我們的應(yīng)用程序?yàn)橛钟蒀WinApp派生而來,所以我們的CTestApp類也有一個m_pMainWnd成員,它所指南的即是CMainFrame類。(需進(jìn)行合適的強(qiáng)制類型轉(zhuǎn)換)。總結(jié)起來有幾點(diǎn)注意: A.在類A中獲得類B的指針時,類A應(yīng)包含類B的頭文件。 B.在很多時候要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,并要注意括號的括法。 由于派生類和父類指針類型的兼容,使明確區(qū)分各個類變得十分重要。在拿不準(zhǔn)的時候,最好加上強(qiáng)制類型轉(zhuǎn)換。
|