MFC單文檔程序架構(gòu)解析
這里我以科院楊老師的單文檔程序來分析一下MFC單文檔的程序架構(gòu),,純屬個(gè)人見解,不當(dāng)之處煩請(qǐng)指教,! 首先我們了解到的是
圖(一) theApp 是唯一一個(gè)在程序形成的時(shí)候就存在的全局變量,,它屬于CstockAppApp類,而CstockAppApp 繼承于CwinApp類,,我們看一下MSDN中CwinApp的繼承關(guān)系如下:
圖(二) 從繼承關(guān)系當(dāng)中,,我們發(fā)現(xiàn)theApp是作為程序的實(shí)體而存在的,是單文檔程序的核心,。 首先分析一下的是CsockAppApp這個(gè)類,,這里面有一個(gè)重要的函數(shù) BOOL CStockAppApp::InitInstance()這個(gè)函數(shù),包含了單文檔程序中重要的信息,,特別要提到的是一下的一段代碼: CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CStockAppDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame windon RUNTIME_CLASS(CStockAppView)); 這里體現(xiàn)了幾個(gè)重要的思想,,第一動(dòng)態(tài)創(chuàng)建和動(dòng)態(tài)附加的一種思想,RUNTIME_CLASS是一個(gè)宏定義,,這里不做展開,,可以理解為最后的函數(shù)返回了實(shí)現(xiàn)了如下的語句 Retrun new CmainFramw 的功能,這里將三個(gè)不同的類對(duì)象附加到CsingleDocTemplate對(duì)象中,,這樣使得整個(gè)程序得以整體成立,。 接下來對(duì)剩下的三個(gè)類對(duì)象做分析 1. CmainFrame類 CmianFrame類作為程序的框架類,其起到了一種容器的作用,,在這個(gè)容器當(dāng)中可以裝在多個(gè)視圖,,菜單,工具等,。要注意的有幾點(diǎn),,第一,因?yàn)?/span>mianfram是沒有視圖的,,因此如果在mainframe相應(yīng)Onpaint消息,自然是可以響應(yīng)這個(gè)消息的,,但是你會(huì)驚奇的發(fā)現(xiàn),,在你的繪制當(dāng)中如何也不會(huì)出現(xiàn)你預(yù)想出現(xiàn)的繪制內(nèi)容,為什么呢? 嘿嘿,,可以想象一下你在一個(gè)word程序里面,,當(dāng)你關(guān)閉了所有的白板(視圖)的時(shí)候,你會(huì)發(fā)現(xiàn)你已經(jīng)無法在編寫文字,,道理是一樣的,,在mainframe里面進(jìn)行繪制,程序是沒有問題,,但是繪制的內(nèi)容是在灰色上面,,windows不予顯示的。 第二點(diǎn)你可以發(fā)現(xiàn)在對(duì)菜單,,和工具條的單擊消息進(jìn)行相應(yīng)的時(shí)候你可以將消息響應(yīng)函數(shù)添加到cmainframe也沒有將消息響應(yīng)函數(shù)調(diào)價(jià)到cview當(dāng)中,,但是你會(huì)驚奇的發(fā)現(xiàn),兩者只在一個(gè)地方相應(yīng)的時(shí)候,,消息響應(yīng)函數(shù)沒有問題都能正確的執(zhí)行,,但是如果同時(shí)對(duì)一個(gè)按鈕或者菜單進(jìn)行單擊消息響應(yīng)的時(shí)候,你會(huì)發(fā)現(xiàn)windows會(huì)執(zhí)行的Cview里面的消息響應(yīng)函數(shù),。分析兩者之間的關(guān)系,,首先Cmianframe的繼承關(guān)系如下:
而對(duì)Cview類而言其繼承類關(guān)系如下圖所示:
可以看出兩個(gè)類之間并沒有直接的關(guān)系,但是我們通過程序的運(yùn)行可以知道消息的響應(yīng)是以Cview中為主的,,可以認(rèn)為存在一種類似于多態(tài)的關(guān)系,。 這里具體的消息路徑如下: 在SDI(單文檔)界面中,菜單響應(yīng)遵循這樣一個(gè)順序:菜單消息先由CMainFrame類接收,,CMainFrame并不直接在內(nèi)部尋找對(duì)應(yīng)的相應(yīng)函數(shù),,而是到CView類尋找。如果CView類有該消息的響應(yīng)函數(shù),,那么就直接調(diào)用CView類中的響應(yīng)函數(shù),,否則,轉(zhuǎn)到CDoc類尋找,,如果CDoc類中存在該消息的響應(yīng)函數(shù),,那么就直接調(diào)用CDoc類中的響應(yīng)函數(shù),否則,,返回到CMainFrame類尋找,。如果CMainFrame類中也沒有,返回到CApp類中尋找,。如果在CApp類中也沒有找到,,表示沒有該菜單的響應(yīng)函數(shù)。
同時(shí)CmainFrame作為整個(gè)程序的框架,,它提供了程序運(yùn)行的基礎(chǔ)環(huán)境,,這里再強(qiáng)調(diào)介紹一下兩點(diǎn) 1. 在CmainFrame中訪問Cview對(duì)象和Cdoc對(duì)象 要訪問這兩個(gè)對(duì)象可以使用全局函數(shù)GetActiveDocument()和GetActiveView()這樣可以獲得Doc對(duì)象和View對(duì)象的實(shí)體了 2. 在CmainFrame中調(diào)用Cview對(duì)象更新窗口,,這里使用方法如下:GetActiveView()->Invalidate(FALSE);// 這一句會(huì)是cview調(diào)用OnDraw消息響應(yīng)函數(shù) GetActiveView()->UpdateWindow();//這句可以加上也可以不加,暫時(shí)沒有發(fā)現(xiàn)不加會(huì)出現(xiàn)什么問題,。 2.Cview類 Cview類作為視圖類,,其可以理解為一張畫布,在這張畫布上可以畫圖,,也可以畫控件,,其重要的函數(shù)有OnDraw這是主要繪圖出現(xiàn)的地方。在View中要實(shí)現(xiàn)重畫的時(shí)候可以按如下方式實(shí)現(xiàn)調(diào)用: void CTestView::OnChangeRect() { // Change Rectangle size. m_rcBox = CRect(20, 20, 210, 210);
// Invalidate window so entire client area // is redrawn when UpdateWindow is called. Invalidate();
// Update Window to cause View to redraw. UpdateWindow(); }
// On Draw function draws the rectangle. void CTestView::OnDraw(CDC* pDC) { // .. Other draw code here.
pDC->Draw3dRect(m_rcBox, 0x00FF0000, 0x0000FF00); } 在Cview內(nèi)中要獲取到CmianFrame可以使用下面的函數(shù): AfxGetMainWnd() 3.doc類對(duì)象,。 個(gè)人覺得單文檔視圖的設(shè)計(jì)模式很接近MVC的設(shè)計(jì)模式,,Model層可以粗略的認(rèn)為是在Doc這個(gè)類對(duì)象里面,在單文檔視圖當(dāng)中Doc對(duì)象充當(dāng)?shù)囊彩菙?shù)據(jù)存儲(chǔ)的類,,可見確實(shí)是有一些MVC設(shè)計(jì)模式的意思,。這里介紹在其他類中要獲取Doc對(duì)象的方法 在Cmianframe中可以使用 GetActiveDocument() 在Cview類中可以使用 這里要注意一點(diǎn),在Cview類中包含了一個(gè)Cdocument的對(duì)象m_pDocument這個(gè)對(duì)象即使指向Doc類的基類對(duì)象的,,而要實(shí)現(xiàn)基類對(duì)象到現(xiàn)在doc類對(duì)象的轉(zhuǎn)換只要添加如下函數(shù)即可 inline CStockAppDoc* CStockAppView::GetDocument() { return (CStockAppDoc*)m_pDocument; } 則可以實(shí)現(xiàn),。
附上三個(gè)類對(duì)象相互訪問方法: 1、主框架(CFrameWnd)中訪問視圖(CView) 應(yīng)該這樣寫:((CMouseKeyView*)GetActiveView())->MyFunc(); 2,、主框架(CFrameWnd)中訪問文檔(CDocument) 3,、在視圖(CView)中訪問文檔(CDocument) 4、在視圖(CView)中訪問框架(CFrameWnd) 這里修改一下,,因?yàn)樯鲜龃a獲取的只是CMainFrame的父類對(duì)象CFrameWnd對(duì)象,,要獲取實(shí)際的CMainFrame對(duì)象可以進(jìn)行如下操作首先在頭文件中添加#include "MainFrm.h" 然后代碼如下: CMainFrame* frm=(CMainFrame*)::AfxGetMainWnd();frm->test(); 就能成功咯 5、在文檔(CDocument)中訪問框架(CFrameWnd) 6,、在文檔(CDocument)中訪問視圖(CView) 圖,將此參數(shù)設(shè)為NULL 7,、在其他類中訪問文檔類(CDocument) |
|