MFC文档、视图、框架的建立
文档将描述MFC框架程序中WinApp , Document Templates, Document, View , Frame创建和所有关系。
CWinApp
在一个系统程序中只有一个CWinApp对象,该对象会被静态的创建并在MFC框架内部实现的WinMain()中进行初始化(动态链接库程序中不会包含一个CWinApp实例且程序的初始化是在DllMain()中进行)
CWinApp负责管理一个Document Template的链表(CPtrList), 在一个程序中通常会有一个或多个 Document Template,这些Document Template一般是在CWinApp类的虚函数InitInstance中从资源文件中加载的
同时WinApp对象拥有全部的框架窗体(Frame Window),主框架窗体(main frame window)必需被记录保存在WinApp对象的m_pMainWnd中;如果想实现个人的设定的化,可以在InitInstance的实现中改写预先由向导设定的m_pMainWnd;一般的,主框架窗体在SDI中为CMainFrame, 而在MDI中则是CMDIFrameWnd
CDoTemplate
Document Template负责管理Ducument的创建和管理, 它拥有全部全部由它创建的Document
在SDI中 CSingleDocTemplate负责跟踪唯一打开的Document
在MDI中CMultiDocTemplate用一个链表(CPtrList)来负责维护全部被打开的Document
CDocTemplate提供虚成员函数来增加或删除文档
CDocTemplate::AddDocument()
CDocTemplate::RemoveDocument()
同时CDocumentTemplate是CDocument的友元类,在CDocument中一个CDocumentTemplate的指针用来指向创建文档的Document Template
CWinApp负责实现OnFileOpen , 将会依次查询全部Document Template
CDocTemplate同时负责与Document和框架窗体关联的界面
CDocTemlate负责新建立的未命名文件的计数 将其命名为untitled X
CDocument
Document是为CDocument Template所有的
Document 负责维护当前显示文档的视图的链表(CPtrList)
Document不负责创建视图但是他们会在视图创建后关联在视图上,且当一个文档关闭(file open /close)时所有的关联的视图都将被关闭;同时最后一个与文档关联的视图关闭时文档也会被关闭
Document 提供结构AddView() RemoveView()来维护视图链表
同时CDocument是CView的友元
在CView中的成员变量CView::m_pDocument用来指向视图所关联的文档
CFrameWnd
包括一些列的派生类CMDIFrameWnd CMDIChildWnd
负责创建在框架的客户区的窗体
***************************************************************************************************************************
遍历应用程序的视图,文档,文档模板
转载自:http://blog.csdn.net/SammyLan/archive/2006/04/07/654341.aspx
void EnumAllView(CDocument*pDoc)
// 遍历文档关联的视图
{
POSITION pos=pDoc->GetFirstViewPosition();
while (pos)
{
CView*pView=pDoc->GetNextView(pos);
/**/
}
}
void EnumAllDocment(CDocTemplate*pDocTemp)
// 遍历文档模板对应的文档
{
POSITION pos=pDocTemp->GetFirstDocPosition();
while (pos)
{
CDocument*pDoc=pDocTemp->GetNextDoc(pos);
if (pDoc)
{
EnumAllView(pDoc);
}
}
}
void EnumAllDocTemp()
// 遍历应用程序的文档模板
{
CDocManager*pDocMan=AfxGetApp()->m_pDocManager;
if (!pDocMan)
{
return ;
}
POSITION pos=pDocMan->GetFirstDocTemplatePosition();
while (pos)
{
CDocTemplate*pDocTemp=pDocMan->GetNextDocTemplate(pos);
if (pDocTemp)
{
EnumAllDocment(pDocTemp);
}
}
}
***************************************************视图中的一些操作*****************************************************
//更新所有视图:
pDoc->UpdateAllViews();
//添加和移除视图
pDoc->AddView(pView);
pDoc->RemoveView(pView);
//无论何时文档数据发生更改,都应该调用
pDoc->SetModifiedFlag();
//同时可以调用
pDoc->IsModified();//获取状态
//应用程序可以通过SetTitle成员函数设置文档对象的标题,也既可以使用SetPathName函数为文档设置完全限定名,用GetPathName函数获取全路径名.可以通过GetDocTemplate获取程序在创建文档的时候将其关联到的文档模板
在CDocTemplate中有一个GetDocString成员函数,可以查询IDR_MAINFRAME字符串的值,注意,没有对应的SetDocString函数。
***************************************************************************************************************************
框架、文档与视图的毁灭
转载自:http://blog.csdn.net/fiolee/archive/2004/08/11/71714.aspx
1、 无文档的多视图程序的毁灭顺序及解决方法
在无文档的多视图程序中,程序主框架、子框架、及视图,在通常情况下,如果你直接关闭程序主框架,程序直接调用destroywindow,子框架及视图则自动清理,但程序不会调用子框架的destroywindow以及postncdestroy两个函数,如果你先关闭视图,关闭的顺序如下,程序先调用子框架的的destroywindow,然后调用视图的postncdestroy,接着就是子框架的postncdestroy,程序里没有调用到视图的destroywindow。
有些情况下,必须保证程序的先子框架关闭,这时候上面这个顺序就会造成程序出错了,正如前面所说,直接关闭主框架时只调用了一个destroywindow函数,其余的函数都不执行了。解决的思路,我们得把程序的毁灭顺序改一改,把子框架的毁灭放在主框架毁灭之前:
CChildFrame *pChildFrame = (CChildFrame *)this->GetActiveFrame();
while (pChildFrame)
{
pChildFrame->DestroyWindow();
pChildFrame = (CChildFrame *)this->GetActiveFrame();
}
通过此循环,可以将所有子框架删除,在循环中,调用的GetActiveFrame函数是获得当前活动子框架,在删除当前活动子框架时,其它的子框架又会变成活动子框架,所以这种方法不会造成死循环。
2、 多文档视图程序的毁灭顺序
它和上面的情况差不多,只是多了一个文档,它的毁灭是在子框架的OnClose之后,子框架的destroywindow之前。
*******************************************************************************************************************************************
文档、文档模板、视图和框架类的互相访问
从该对象 | 如何访问其他对象 |
全局函数 | 调用全局函数AfxGetApp可以得到CWinApp应用类指针 |
应用 | AfxGetApp()->m_pMainWnd为框架窗口指针;用CWinApp::GetFirstDocTemplatePostion、CWinApp::GetNextDocTemplate来遍历所有文档模板 |
文档 | 调用CDocument::GetFirstViewPosition,CDocument::GetNextView来遍历所有和文档关联的视图;调用CDocument:: GetDocTemplate 获取文档模板指针 |
文档模板 | 调用CDocTemplate::GetFirstDocPosition、CDocTemplate::GetNextDoc来遍历所有对应文档 |
视图 | 调用CView::GetDocument 得到对应的文档指针;调用CView::GetParentFrame 获取框架窗口 |
文档框架窗口 | 调用CFrameWnd::GetActiveView 获取当前得到当前活动视图指针;调用CFrameWnd::GetActiveDocument 获取附加到当前视图的文档指针 |
MDI 框架窗口 | 调用CMDIFrameWnd::MDIGetActive 获取当前活动的MDI子窗口(CMDIChildWnd) |
我们列举一个例子,综合应用上表中的函数,写一段代码,它完成遍历文档模板、文档和视图的功能:
CMyApp *pMyApp = (CMyApp*)AfxGetApp(); // 得到应用程序指针 POSITION p = pMyApp->GetFirstDocTemplatePosition();// 得到第1个文档模板 while (p != NULL) // 遍历文档模板 { CDocTemplate *pDocTemplate = pMyApp->GetNextDocTemplate(p); POSITION p1 = pDocTemplate->GetFirstDocPosition();// 得到文档模板对应的第1个文档 while (p1 != NULL) // 遍历文档模板对应的文档 { CDocument *pDocument = pDocTemplate->GetNextDoc(p1); POSITION p2 = pDocument->GetFirstViewPosition(); // 得到文档对应的第1个视图 while (p2 != NULL) // 遍历文档对应的视图 { CView *pView = pDocument->GetNextView(p2); } } } |
由此可见,下面的管理关系和实现途径都是完全类似的:
(1)应用程序之于文档模板;
(2)文档模板之于文档;
(3)文档之于视图。
下面的图1、图2 分别给出了一个多文档/视图框架MFC程序的组成以及其中所包含类的层次关系。