瞭解文檔和視圖的相互作用關係是編寫MFC程序的基本功。但是MFC的應用程序框架把文檔和視圖之間的關係封裝了起來,初學的朋友往往不得要領,因此寫程序往往被侷限於在用嚮導生成的框架中。本文希望能夠儘可能說明白文檔視圖框架之間是如何進行作用,希望能給一些朋友帶來小小的幫助。
幾個概念:
(雖然大家都知道了,雷神還是要重申一次)
文檔對象:是用來保存數據的。
視圖對象:是用來顯示和編輯數據的。
應用程序框架:框架是用來管理不同文檔顯示界面的。例如你有一個數據網格顯示界面,還有一個圖形顯示界面,它們的數據可能都來自你的文檔,但是視圖不同,怎麼辦用框架。爲什麼不用視圖?爲的是把界面管理獨立的拿出來。
文檔模板:MFC把文檔/視圖/框架視爲一體,只要你創建文檔/視圖框架結構的程序,必定會爲你創建這三個類。這個工作在在應用程序初始化時完成,如下:
BOOL CMyHtmlApp::InitInstance()
{
//。。。。。。
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyHtmlDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMyHtmlView));
AddDocTemplate(pDocTemplate);
//。。。。。。
}
單文檔:就是一次只能打開一個文件,和你的文檔類型支持的多少無關。你完全可以做一個單文檔的支持所有圖象格式的程序,只不過它一次只能打開一個文檔罷了。
多文檔:就是你可以打開多個文件,和文檔類型也無關。你也可以作一個可以同時打開多個文檔的程序,但它只支持一種文檔類型。
何時需要文檔/視圖框架結構?
首先你可以不使用文檔視圖這種框架結構,即便是在MFC中。你可以在你需要的時候選擇使用這種方式。你可以完成一個只有視圖沒有文檔的程序,例如一個基於對話框的應用。
哪什麼時候需要呢?
當你想將你的數據層和界面層分開的時候。
通常我們對數據的操作放在文檔類中,例如存取,打開,關閉。在這裏你可以盡情的對你的數據進行操作,如果你需要,在對數據進行了改變後,對視圖做一下更新,那麼程序會將你對數據所做的改變呈現給你的程序的用戶。由此可見視圖的作用就是提供一個用戶和數據之間進行數據交換的界面,它的作用就是在需要的時候顯示數據,並在需要的時候提供輸入界面。當用戶輸入後實際的數據操作工作是由文檔類來做的。那框架類有在做什麼呢?
框架類是爲了便於管理你的文檔類和視圖類而存在的。通常我們的操作都是通過視圖窗口完成,消息由視圖進行接收並且進行處理。所以消息映射定義一般在視圖中。但如果一個應用同時擁有多個視而當前活動視沒有對消息進行處理則消息會發往框架窗口。另外框架窗口可以方便的處理非窗口消息。
再來說一邊典型的單文檔程序的生成過程(不完整,只挑有用的)
1、 CwinApp對象被建立,這個對象是全局的且只能有一個,名字叫theApp。這時你可以完成一些工作,例如對註冊表的操作,(如果你想寫一個不修改註冊表的軟件,需要在這裏做寫工作)
2、 在InitInstance()函數中創建文檔模板,文檔模板以CruntimClass靜態成員指針做構造參數。
3、 執行MFC框架默認的命令行參數。命令行參數有很多其中之一是,Cmd1它會創建一個新文件。(如果沒有命令行參數則執行默認的ID_FILE_NEW)
4、 文檔模板的實例根據三個類的動態創建信息創建出文檔、視圖、框架。
5、 對文檔、視圖、框架進行初始化。
我們對文檔,視圖,框架如何產生以及他們的用途有了一定的瞭解,如何有效的使用它們呢。
文檔,視圖,框架之間的相互作用。
由上面的典型的單文檔程序的生成過程可以看出一個完整的應用一般由四個類組成:CWinApp應用類,CFrameWnd框架類,CDocument文檔類,CView視圖類。我將四個類常用的成員函數列出,大家一看便知。不過參數,返回值均未列出,大家可以從MSDN上了解更多。幾個重要的虛函數也未做說明。大家自己看吧。
通過全局函數AfxGetApp可以得到CWinApp應用類的全局對象theApp.
CwinApp
數據成員:
m_pszAppName 應用程序名稱
m_pszExeName 可執行文件的名稱
m_pszProfileName INI文件的名
m_pszRegistryKey 註冊表或INI文件的KEY
m_hInstance 實例的句柄
m_pMainWnd 爲框架窗口指針
成員函數:
InitInstance() //初始化
ParseCommandLine() //完成命令行的解析處理
CFrameWnd
GetActiveDocument() //得到當前活動文檔指針
GetActiveView() //得到當前活動視指針
SetActiveView() //設置當前視圖爲活動視圖
CDocument
OnNewDocument()
OnOpenDocument()
OnSaveDocument()
OnFileClose()
//以上是用來對文檔的操作
GetFirstViewPosition() //文檔對象鏈表中的第一個文檔位置
GetNextView() //下一個
//以上是用來遍歷所有和文檔關聯的視圖
GetDocTemplate()得到文檔模板指針
AddView() //增加一個視圖
RemoveView() //刪除一個視圖
UpdateAllView() //更新所有視圖
Cview
GetDocument()得到對應的文檔指針
其他的就不列出了,大家還是看MSDN。你可以直接查看CWinApp應用類,CFrameWnd框架類,CDocument文檔類,CView視圖類的類成員。
最後說說幾個常見到的問題。
1,爲什麼在對話框的應用程序中沒有發現文檔模板?
默認的對話框程序沒有使用文檔/視圖框架結構。
2 ,如果我使用數據庫作爲數據源是否意味着可以不需要文檔類?
看你自己,但是我建議使用。因爲可以文檔,視圖這一個清晰方便的框架結構,以及方便完成三者之間的相互作用。
------------------------------------------------------------------------------------------------------------
1、主框架(CFrameWnd)中訪問視圖(CView)
CView* GetActiveView() const;
通常定義的視圖爲CView的派生類,在調用自定義視圖對象的方法時
應該這樣寫:((CMouseKeyView*)GetActiveView())->MyFunc();
2、主框架(CFrameWnd)中訪問文檔(CDocument)
GetActiveDocument,返回CDocument對象;
3、在視圖(CView)中訪問文檔(CDocument)
inline CMouseKeyDoc* CMouseKeyView::GetDocument()
{return (CMouseKeyDoc*)m_pDocument;}
4、在視圖(CView)中訪問框架(CFrameWnd)
CFrameWnd* GetParentFrame() const;
5、在文檔(CDocument)中訪問框架(CFrameWnd)
CWnd* AfxGetMainWnd();
CWnd* AfxGetApp()->m_pMainWnd;
6、在文檔(CDocument)中訪問視圖(CView)
UpdateAllViews
功能:通知所有的視圖文檔已被修改的信息
原型:
void UpdateAllViews(
CView* pSender, // 要更新的視圖指針,如果希望更新所有視
圖,將此參數設爲NULL
LPARAM lHint=0L, // 包含更改消息的通知
CObject* pHint=NULL // 保管更改消息的對象
}
7、在其他類中訪問文檔類(CDocument)
CDocument* GetDocument()
{
CFrameWnd* frm=(CFrameWnd*)::AfxGetMainWnd();
ASSERT(frm);
CDocument* pDoc=frm->GetActiveDocument();
ASSERT(pDoc);
ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CMouseKeyDoc)));
return (CMouseKeyDoc*)pDoc;
}
[注:資料轉載自網上]