1. 程式人生 > >MFC中獲取各種類(文件、檢視、框架、應用程式)指標的方法

MFC中獲取各種類(文件、檢視、框架、應用程式)指標的方法

  對於初學者來說,在MFC中獲得各種類的指標是個障礙。如:要獲得另一窗體檢視類中的某控制元件指標,首先必須獲得目標檢視指標,然後再通過該檢視指標用GetDlgItem函式才可獲得控制元件指標。

只考慮文件、檢視和框架視窗間的關係,常用的指標獲取方法如下:

全域性函式AfxGetApp可以得到CWinApp應用類指標
AfxGetApp()->m_pMainWnd為框架視窗指標
在框架視窗中:CFrameWnd::GetActiveDocument得到當前活動文件指標
在框架視窗中:CFrameWnd::GetActiveView得到當前活動視指標
在視中:CView::GetDocument得到對應的文件指標
在文件中:CDocument::GetFirstViewPosition,CDocument::GetNextView用來遍歷所有和文件關聯的視。
在文件中:CDocument::GetDocTemplate得到文件模板指標
在多文件介面中:CMDIFrameWnd::MDIGetActive得到當前活動的MDI子視窗

MFC中一些類的指標獲取方法如下:

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) 從一個檢視類取得另一檢視類的指標
16) 獲取分割檢視中各個檢視的指標

  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(已建立)指標

  CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;
  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項中可以得到。

16) 獲取分割檢視中各個檢視的指標
CSplitterWnd m_wndSplitter;
m_wndSplitter.CreateStatic(this, 1, 2);//分割成一行兩列
m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftPaneView), CSize(10, 10), pContext);
m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CRightPaneFrame), CSize(0, 0), pContext);
//獲取左邊檢視的兩種方法
CLeftPaneView* pLeftPaneView     = (CLeftPaneView*)   m_wndSplitter.GetPane(0,0);
//上一句可以用下句代替:
//CLeftPaneView* pLeftPaneView  = (CLeftPaneView *)GetActiveView();
//獲取右邊檢視
pLeftPaneView->m_pRightPaneFrame = (CRightPaneFrame*) m_wndSplitter.GetPane(0,1);