在MFC類中各種類的指標的獲取和應用

scq2099yt發表於2008-05-26

http://www.cnblogs.com/duguguiyu/archive/2007/06/22/792511.html

 

 

獲得CWinApp

獲得CMainFrame

獲得CChildFrame

獲得CDocument

獲得CView

在CWinApp中

 

AfxGetMainWnd()

m_pMainWnd

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()

SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

SDI:AfxGetMainWnd()->GetActiveView()  
MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()
在CMainFrame中

AfxGetApp()

theApp

 

MDIGetActive()

GetActiveFrame()

SDI:GetActiveView()->GetDocument()  
MDI:MDIGetActive()->GetActiveView()->GetDocument()  
SDI:GetActiveView()  
MDI:MDIGetActive()->GetActiveView()
在CChildFrame中

AfxGetApp()

theApp

GetParentFrame()

 

GetActiveView()->GetDocument()   GetActiveView()
在CDocument中

AfxGetApp()

theApp

AfxGetMainWnd()  

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()

  POSITION   pos   =   GetFirstViewPosition();GetNextView(pos)  
在CView中

AfxGetApp()

theApp

AfxGetMainWnd()   GetParentFrame()   GetDocument()  
在其他類中

AfxGetApp()

AfxGetMainWnd()  

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()

SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

SDI:AfxGetMainWnd()->GetActiveView()  
MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()

理一理MFC的這幾個類的關係,可以很容易明白上面的這些亂七八糟的邏輯。
App是應用域,所有的域中的東西都可以通過全域性函式訪問到它。
MainFrame是主框架,也基本可以用全域性函式訪問到。
MainFrame下是若干個ChildFrame,ChildFrame中若干個View和Document(可能不成對),ChildFrame管理著View,View和Document進行互操作。
因此整體框架就出來了,一般除了直接應用的關係都可以通過MainFrame-->Active ChildFrame-->Active View-->Document這條線進行訪問

關於MFC下的文件和檢視以及框架之間的訪問, 這些問題已經是老生常談了,但我覺得還是都沒有詳細的說明,特

別是對於英語較差的人,我檢視了一些blog,總結了一下!希望對和我一樣的人有點幫助!
一:
      1:   因為對於SDI程式,主框架視窗就是文件框窗(如果這個也不知道,就要檢視一下MFC下的單文件的構成原理了).
          下面所說的是關於單文件的.          
         
        例子: 在CMainFrame框架中如何得到檢視類的指標.
                    可以 先得到框架指標,然後呼叫 GetActiveView 函式指向當前活動視.

C **View * pView;
                 pView=(C**View*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveView();

          當然這些也許都知道是這麼用的,但真正的m_pMainWnd和AfxGetApp()是什麼意思也許有的人不明白.
         大家也許都知道如何在App中獲得MainFrame指標(框架類): CWinApp 中的 m_pMainWnd變數就是CMainFrame的指標.

   所以在別的類下也可以先得到m_pMainWnd,就得到了MainFrame的指標. 所以得到檢視類的指標,必先 得到CFrameWnd的指標m_pMainWnd,然後在呼叫FrameWnd下的GetActiveView 就指向當前活動視.
m_pMainWnd的由來:
      每一個MFC應用程式都有一個CWinApp派生類的物件。這個物件對應著程式的主執行緒。而 CWinApp 類中有一個 CWnd * m_pMainWnd 成員變數。這個成員變數記錄了應用程式的主視窗。
當你新建一個MFC應用程式的時候,在 InitInstance虛擬函式裡都會出現對 m_pMainWnd 賦值的語句.唯一的例外是單文件介面的MFC應用程式,你無法在 InitInstance 函式裡看到這段程式碼,因為它已經被隱藏在 ProcessShellCommand 這個函式裡了。由此你就可以下結論了:只要建立自己的視窗類,就要把這個類的物件賦值給 m_pMainWnd .而這個成員只能在C**APP類中才可以使用,所以怎樣使用這個CWinApp類裡的CWnd 型別的變數來得到主框架視窗的指標呢??
AfxGetApp函式才可以 , 因為AfxGetApp()得到的是CWinApp類的物件,且AfxGetApp返回值為CWinApp物件指標,就是MFC生成的C**App.cpp中定義的那個物件(物件theApp的指標)。

因為你是在自己建立的專案中得到CWndApp成員函式或者成員變數,所以你必須強制轉換為你自己的專案中的類,才能找到成員函式或者變數.
注: 在單文件中,獲得視指標的最簡單的方法還是
((C**View *)CFrameWnd::GetActiveView())
             
          2:     當然在FrameWnd中也可以得到文件類的指標:
                       CMyDocument* pDoc;
                       pDoc=(CMyDocument*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveDocument();

        
          3:     由上面可以知道:在View中怎樣獲得MainFrame指標
CMainFrame *pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd;

注: 從檢視類中獲得主幀視窗類指標:用函式:CWnd::GetParentFrame()或AfxGetMainWnd()也
可達到目的。GetParentFrame()的工作原理是在父視窗鏈中搜尋,直到找到CFrameWnd或其派生類為止,並返回其指標。

((CMainFrame *)CWnd::GetParentFrame())
或者
((CMainFrame *)AfxGetMainWnd())
        
二:
當然對於MDI程式,由於子視窗才是文件框窗,因此首先要用GetActiveFrame()取得活動子框架視窗,然後通過該子視窗獲取活動檢視和文件:

                 CMDIChildWnd* pChild=(CMDIChildWnd*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)-            

        >GetActiveFrame();

取得活動檢視:
CMyView* pView=(CMyView*)pChild->GetActiveView();

取得活動文件:
CMyDocument* pDoc=pChild->GetActiveDocument();


注: 也可以用這種方法來得到多文件中的視指標
//獲得活動子框架視窗
CMDIChildWnd* pChild=(CMDIChildWnd*)GetActiveFrame();
//或:
CMDIChildWnd* pChild=MDIGetActive();
//獲得活動子幀視窗的活動檢視
CMyView* pView=(CMyView*)pChild->GetActiveView();


三:
1.   從檢視類獲得文件類的指標
            在檢視類中需要引用文件類的地方之前,使用以下語句:
C*Doc *pDoc=(C*Doc*)GetDocument();
以後便可使用pDoc指標訪問文件類。
2.    從文件類取得檢視類的指標 CDocument類提供了兩個函式用於檢視類的定位:

   GetFirstViewPosition()和GetNextView()

注意:GetNextView()括號中的引數用的是引用方式,因此執行後值可能改變.GetFirstViewPosition()用於

返 回第一個檢視位置(返回的並非檢視類指標,而是一個POSITION型別值),GetNextView()有兩個功能:返回下一個檢視類的指標以及用引用 調動的方式來改變傳入的POSITION型別引數的值。很明顯,在Test程式中,只有一個檢視類,因此只需將這兩個函式呼叫一次即可得到 CTestView的指標如下(需定義一個POSITION結構變數來輔助操作):

    C*View* pView;
POSITION pos=GetFirstViewPosition();
pView=GetNextView(pos);

這 樣,便可到了C*View類的指標pView.執行完成幾句後,變數pos=NULL,因為沒有下一個檢視類,自然也沒有下一個檢視類的 POSITION.但是之幾條語句太簡單,不具有太強的通用性和安全特徵;當象前面說的那樣,當要在多個檢視為中返回某個指定類的指標時,我們需要遍歷所 有檢視類,直到找到指定類為止。判斷一個類指標指向的是否某個類的例項時,可用IsKindOf()成員函式時行檢查.

如:
pView->IsKindOf(RUNTIME_CLASS(C*View));
即可檢查pView所指是否是C*View類。
有了以上基礎,我們已經可以從文件類取得任何類的指標。為了方便,我們將其作為一個文件類的成員函式,它有一個引數,表示要獲得哪個類的指標。實現如下:
          CView* C*Doc::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為指標。
至於強制型別轉換也是為了安全特性考慮的,因為從同一個基類之間的指標型別是互相相容的。這種強制型別轉換也許並不必要,但能避免一些可能出現的麻煩。

 

 

更多技術文章請參看施昌權的個人網站: http://www.joyvc.cn

 

 

相關文章