【轉】
VC MFC SDI/MDI架構各部分指標擷取方式
2010-12-24 19:17
VC MFC SDI/MDI架構各部分指標擷取方式來源: 編輯:中國人才庫 更新日期:2008-6-14 瀏覽:531前人在CSDN總結的,曾經協助過我,整理總結一下,希望也能協助一下別人。
|
獲得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這條線進行訪問,這應該叫什麼來自?萬能方法吧^_^。
http://hi.baidu.com/blackfox1983/blog/item/2538071b3a4f66d0ad6e7583.html
關於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為指標。
至於強制類型轉換也是為了安全特性考慮的,因為從同一個基類之間的指標類型是互相相容的。這種強制類型轉換也許並不必要,但能避免一些可能出現的麻煩