日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC中的Document-View结构

發(fā)布時間:2023/12/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC中的Document-View结构 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

MFC之所以為Application Framework,最重要的一個特征就是它能夠?qū)⒐芾頂?shù)據(jù)的程序代碼和負責顯示數(shù)據(jù)的程序代碼分離開來,而這種能力有Document/View提供。
想要實現(xiàn)數(shù)據(jù)管理和顯示的分離,需要搞清楚一些幾個問題:
1. ?程序的哪個部分持有數(shù)據(jù)
2. ?程序的哪個部分負責更新數(shù)據(jù)
3. ?如何以多種方式顯示數(shù)據(jù)
4. ?如何讓數(shù)據(jù)的更改有一致性
5. ?如何實現(xiàn)數(shù)據(jù)持久化
6. ?如何管理使用者接口。不同的數(shù)據(jù)類型可能需要不同的使用者接口,而一個程序可能管理多種類型的數(shù)據(jù)。
其實Document/View結(jié)構(gòu)與當下很流行的MVC架構(gòu)有異曲同工之妙。其間的對應關(guān)系可以這樣認為:M-Document, V-View,C-Document Template。

Document
Document其實就是指數(shù)據(jù)。Document在MFC的CDocument中被實例化。CDocument本身并無實際用途,它只提供一個框架。當我們開發(fā)程序時,應該從CDocument派生出一個屬于自己的Document類,并且在類中聲明一些成員變量,用以容納數(shù)據(jù)。然后再(至少)改寫專門負責檔案讀寫操作的Serialize函數(shù)。當然,APPWizard會為我們搭好框架,我們只要往里面填就行了。例如:
類聲明中:virtual void Serialize(CArchive& ar);
類定義中:
void CMyDoc::Serialize(CArchive& ar){?? ?if (ar.IsStoring())?? ?{?? ??? ?// TODO: add storing code here?? ?}?? ?else?? ?{?? ??? ?// TODO: add loading code here?? ?}}
View
View負責呈現(xiàn)Document中的數(shù)據(jù)。View在MFC的CView中被實例化。當我們開發(fā)自己的程序時,應該從CView派生出一個屬于自己的View類,并且在類中(至少)改寫專門負責顯示數(shù)據(jù)的OnDraw函數(shù)(針對屏幕)或Onprint函數(shù)(針對打印機)。同樣,APPWizard也會為我們搭好框架,如下:
類聲明中:virtual void OnDraw(CDC* pDC); ?// overridden to draw this view
類實現(xiàn)中:
void CMFCView::OnDraw(CDC* pDC){?? ?CMFCDoc* pDoc = GetDocument();?? ?ASSERT_VALID(pDoc);?? ?// TODO: add draw code for native data here}
由于CView派生子CWnd,所以它可以接收一般的Windows消息(如WM_SIZE、WM_PAINT等),又派生自CCmdTarget,所以它可以接收自菜單或工具欄的WM_COMMAND消息。
在傳統(tǒng)的C/SDK程序中,當窗口函數(shù)收到WM_PAINT時,我們開始獲得DC并繪制畫面。而在MFC中,一旦WM_PAINT發(fā)生,Framework就會自動調(diào)用OnDraw函數(shù)。
View其實是一個沒有邊框的窗口。真正出現(xiàn)時,其外圍還有一個有邊框的窗口,我們稱之為Frame窗口。
Frame
? ? Frame負責窗口顯示時的UI管理。之所以不然View插手這件事而由Frame全權(quán)處理,涉及到框架設(shè)計層面的考慮。有時候功能之間需要一定的關(guān)聯(lián)度,但是這種關(guān)系又不能太強。把UI管理隔離出來,可以降低彼此之間的依賴程度,也可以是該功能重復適用于各種場合。
Document Template
MFC把Document/View/Frame視為三位一體,這個整體就由DocumentTemplate來掌管。
如果程序中能夠處理多種數(shù)據(jù)類型,就必須制造多個Document Template出來,并使用AddDocTemplate函數(shù)將它們一一加入系統(tǒng)之中。這和程序是不是MDI(Multiple Document Interface,就是所謂的多文檔界面)無關(guān)。如果程序支持多種數(shù)據(jù)類型,但卻是個SDI(Single Document Interface,就是所謂的單文檔界面),那只不過表示我們每次只能開啟一份文件罷了。
CDocTemplate管理CDocument/CView/CFrameWnd
由Document Template來管理Document/View/Frame,那么誰又是Document Template的管理者呢?其實是CWinApp,可以看其InitInstance函數(shù)中的操作:
{?? ?CMultiDocTemplate* pDocTemplate;?? ?pDocTemplate = new CMultiDocTemplate(?? ??? ?IDR_MFCTYPE,?? ??? ?RUNTIME_CLASS(CMFCDoc),?? ??? ?RUNTIME_CLASS(CChildFrame), // custom MDI child frame?? ??? ?RUNTIME_CLASS(CMFCView));?? ?AddDocTemplate(pDocTemplate);}
聯(lián)系文件的新建和打開操作,如下圖(摘自:《深入淺出MFC》):

當使用者單擊【文件/新建】命令項時,根據(jù)APPWizard為我們所做的Message Map( ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ?),此命令由CWinApp::OnFileNew函數(shù)接手處理。后者調(diào)用CDocManager::OnFileNew,后者再調(diào)用CWinApp::OpenDocumentFile,后者再調(diào)用CDocManager:: OpenDocumentFile,后者再調(diào)用CMultiDocTemplate::OpenDocumentFile。最后調(diào)用的函數(shù)主要操作如下(定義于DOCMULTI.CPP):
CDocument*CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
? ? BOOLbMakeVisible)
{
? ? CDocument*pDocument =?
CreateNewDocument();
? ? if(pDocument == NULL)
? ? {
? ? ? ?TRACE0("CDocTemplate::CreateNewDocumentreturned NULL.\n");
? ? ? ?AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
? ? ? ?returnNULL;
? ? }
? ? ASSERT_VALID(pDocument);
?
? ? BOOLbAutoDelete = pDocument->m_bAutoDelete;
? ? pDocument->m_bAutoDelete= FALSE; ? // don't destroy if somethinggoes wrong
? ? CFrameWnd*pFrame = CreateNewFrame(pDocument, NULL);
? ? pDocument->m_bAutoDelete= bAutoDelete;
? ? if(pFrame == NULL)
? ? {
? ? ? ?AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
? ? ? ?deletepDocument; ? ? ? // explicit delete onerror
? ? ? ?returnNULL;
? ? }
? ? ASSERT_VALID(pFrame);
?
? ? if(lpszPathName == NULL)
? ? {
? ? ? ?//create a new document - with default document name
? ? ? ? ? ?……
? ? }
? ? else
? ? {
? ? ? ?//open an existing document
? ? ? ?……
? ? }
?
? ? InitialUpdateFrame(pFrame,pDocument, bMakeVisible);
? ? returnpDocument;
}
其中CreateNewDocument函數(shù)(定義于DOCTEMPL.CPP)的操作如下:
CDocument* CDocTemplate::CreateNewDocument(){?? ?// default implementation constructs one from CRuntimeClass?? ?if (m_pDocClass == NULL)?? ?{?? ??? ?TRACE0("Error: you must override CDocTemplate::CreateNewDocument.\n");?? ??? ?ASSERT(FALSE);?? ??? ?return NULL;?? ?}?? ?CDocument* pDocument = (CDocument*)m_pDocClass-> CreateObject();//動態(tài)創(chuàng)建Document對象?? ?if (pDocument == NULL)?? ?{?? ??? ?TRACE1("Warning: Dynamic create of document type %hs failed.\n",?? ??? ??? ?m_pDocClass->m_lpszClassName);?? ??? ?return NULL;?? ?}?? ?ASSERT_KINDOF(CDocument, pDocument);?? ?AddDocument(pDocument);?? ?return pDocument;}
正如所料,其中動態(tài)產(chǎn)生了Document對象。
CreateNewFrame函數(shù)的主要操作如下:
CFrameWnd*CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{
? ? if(pDoc != NULL)
? ? ? ?ASSERT_VALID(pDoc);
? ? //create a frame wired to the specified document
?
? ? ASSERT(m_nIDResource!= 0); // must have a resource ID to load from
? ? CCreateContextcontext;
? ? context.m_pCurrentFrame= pOther;
? ? context.m_pCurrentDoc= pDoc;
? ? context.m_pNewViewClass=?
m_pViewClass;
? ? context.m_pNewDocTemplate= this;
……
? ? CFrameWnd*pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();//動態(tài)創(chuàng)建Document Frame對象
? ? ……
? ? //create new from resource
? ? if(!pFrame->LoadFrame(m_nIDResource,
? ? ? ? ? ?WS_OVERLAPPEDWINDOW| FWS_ADDTOTITLE, ? // default framestyles
? ? ? ? ? ?NULL, &context))
? ? {
? ? ? ?TRACE0("Warning:CDocTemplate couldn't create a frame.\n");
? ? ? ?//frame will be deleted in PostNcDestroy cleanup
? ? ? ?returnNULL;
? ? }
?
? ? //it worked !
? ? returnpFrame;
}
顯然上面動態(tài)創(chuàng)建了所需的Frame,但是View卻是蹤跡全無。真實如此嗎?實則不然。上代碼出現(xiàn)了一個context變量,該變量有一個字段指向m_pViewClass?;叵隒FrameWnd::Create操作的最后一個參數(shù),它正是context。當CFrameWnd收到WM_CREATE時會觸發(fā)CFrameWnd::OnCreate(由Message Map指定),其調(diào)用次序如下:
CFrameWnd::OnCreate-> CFrameWnd::OnCreateHelper -> CFrameWnd::OnCreateClient -> CFrameWnd::CreateView
其中最后調(diào)用的函數(shù)(定義于WINFRM.CPP)主要操作如下:
CWnd* CFrameWnd::CreateView(CCreateContext*pContext, UINT nID)
{
? ? ……
? ? CWnd*pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();//動態(tài)生成View對象
? ? ……
? ? //views are always created with a border!
? ? if(!pView->Create(NULL, NULL,AFX_WS_DEFAULT_VIEW,
? ? ? ?CRect(0,0,0,0),this, nID, pContext))
? ? {
? ? ? ?TRACE0("Warning:could not create view for frame.\n");
? ? ? ?returnNULL; ? ? ? ?// can't continue without aview
? ? }
?
? ? if(afxData.bWin4 && (pView->GetExStyle() & WS_EX_CLIENTEDGE))
? ? {
? ? ? ?//remove the 3d style from the frame, since the view is
? ? ? ?// ?providing it.
? ? ? ?//make sure to recalc the non-client area
? ? ? ?ModifyStyleEx(WS_EX_CLIENTEDGE,0, SWP_FRAMECHANGED);
? ? }
? ? returnpView;
}
由上可見,不僅View對象被動態(tài)生成,其對應的實際窗口也以Create函數(shù)產(chǎn)生出來。
CDocTemplate、CDocument、CView、CFrameWnd關(guān)聯(lián)關(guān)系
1. ?CWinApp擁有一個對象指針:CDocManager * m_pDocManager
2. ?CDocManager擁有一個指針鏈表CPtrList m_templateList,用來維護一系列的DocumentTemplate。應用程序在CMyWinApp::InitInstance中以AddDocTemplate將這些Document Templates加入到有CDocManager所維護的鏈表之中。
3. ?CDocTemplate擁有三個成員變量,分別持有Document、View、Frame的CRuntimeClass指針,另有一個成員變量m_nIDResource,用來表示此Document顯示時應該采用的UI對象。這四份數(shù)據(jù)在CMyWinApp::InitInstance函數(shù)構(gòu)造CDocTemplate時指定,稱為構(gòu)造函數(shù)的參數(shù)。
4. ?CDocument有一個成員變量CDocTemplate * m_pDocTemplate,回指其DocumentTemplate;另外有一個成員變量CPtrList m_viewList,表示它可以同時維護一組Views。
5. ?CFrameWnd有一個成員變量CView * m_pViewActive,指向當前活動的View。
6. ?CView有一個成員變量CDocument * m_pDocument,指向相關(guān)的Document。
關(guān)系圖示如下(該圖作者水平很高,無法超越,只有借花獻佛了):

原文:https://blog.csdn.net/wzxq123/article/details/51981507?
?

總結(jié)

以上是生活随笔為你收集整理的MFC中的Document-View结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。