您的位置:首页 > 其它

文档、视图、框架窗口、文档模板之间的相互关系

2011-09-16 11:05 459 查看
要了解 文档、视图、框架窗口、文档模板之间的相互关系,关键要理解他们的结构

1、首先应该对 CWinApp类有充分的了解

它包含并管理着应用程序的文档/视窗的所有信息。它有一个成员变量

CDocManager * m_pDocManager,此变量是文档/视窗的管理器,m_templateList

是CDocManager里的一个列表,此列表里保存了所有文档模板的指针,当用户调用

CWinApp::AddDocTemplate( pDocTemplate ) 后该pDocTemplate存入了

CWinApp::m_pDocManager::m_templateList里。

CWinApp::GetFirstDocTemplatePosition()

CWinApp::GetNextDocTemplate(POSITION& pos)

是遍例所有的文档模板指针。

2、上面我们提到了文档模板(CMultiDocTemplate(我们主要针对对文档)),

这是一个极重要的类。CMultiDocTemplate::m_docList保存的所有该种文档的

文档实例的指针列表。下面两个函数用于维护CMultiDocTemplate::m_docList数据

CMultiDocTemplate::AddDocument(CDocument* pDoc);

CMultiDocTemplate::RemoveDocument(CDocument* pDoc);



CMultiDocTemplate::GetFirstDocPosition() const;

CMultiDocTemplate::CDocument* GetNextDoc(POSITION& rPos) const;

用于遍例该文档类型所有文档实例。

3、上面提到文档(CDocument)

CDocument 我们最熟悉不过了。每一个文档实例可有多个视与之相对应。

CDocument::m_viewList用来保存所有与此文档实例相关的View

CDocument::GetDocTemplate 可获得CMultiDocTemplate;

4、CView 他是放在CMDIChildWnd里的,每一个CMDIChildWnd有一个View

CView::GetDocument可获得与此视相关的CDocument

CView::GetParentFrame() 可获得CMDIChildWnd;

通过以上分析可见CWinApp,CMDIChildWnd,CView,CDocument,CMultiDocTemplate之间知道其中一个实例

必可知道其他所有几个实例,CWinApp统领全局,任何时候,只要获得CWinApp实例,则所有的文档模板,

文档实例,视,Frame窗口均可被枚举出来。AfxGetApp() 获得CWinApp实例指针。
***************************************************************************************************************

1) 在View中获得Doc指针

2) 在App中获得MainFrame指针

3) 在View中获得MainFrame指针

4) 获得View(已建立)指针

5) 获得当前文档指针

6) 获得状态栏与工具栏指针

7) 获得状态栏与工具栏变量

8) 在Mainframe获得菜单指针

9) 在任何类中获得应用程序类

10) 从文档类取得视图类的指针(1)

11) 在App中获得文档模板指针

12) 从文档模板获得文档类指针

13) 在文档类中获得文档模板指针

14) 从文档类取得视图类的指针(2)

15) 从一个视图类取得另一视图类的指针

VC中编程对于刚刚开始学习的同学,最大的障碍和问题就是消息机制和指针获取与

操作。其实这些内容基本上是每本VC学习工具书上必讲的内容,而且通过MSDN很多

问题都能解决。下面文字主要是个人在编程中指针使用的一些体会,说的不当的地

方请指正。一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架,

无论是多文档还是单文档,都存在指针获取和操作问题。下面这节内容主要是一般

的框架,然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先

一般获得本类(视,文档,对话框都支持)实例指针this,用this的目的,主要可以通

过类中的函数向其他类或者函数中发指针,以便于在非本类中操作和使用本类中的

功能。

1) 在View中获得Doc指针 CYouSDIDoc *pDoc=GetDocument();一个视只能有一个文

档。

2) 在App中获得MainFrame指针

CWinApp 中的 m_pMainWnd变量就是MainFrame的指针

也可以: CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();

3) 在View中获得MainFrame指针 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()->m_pMainWnd;

4) 获得View(已建立)指针CyouView *pView=(CyouView *)pMain->GetActiveView();

5) 获得当前文档指针 CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd->GetActiveDocument();

6) 获得状态栏与工具栏指针 CStatusBar * pStatusBar=(CStatusBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);

CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);

7) 如果框架中加入工具栏和状态栏变量还可以这样

(CMainFrame *)GetParent()->m_wndToolBar;

(CMainFrame *)GetParent()->m_wndStatusBar;

8) 在Mainframe获得菜单指针 CMenu *pMenu=m_pMainWnd->GetMenu();

9) 在任何类中获得应用程序类

用MFC全局函数AfxGetApp()获得。

10) 从文档类取得视图类的指针

我是从http://download.cqcnc.com/soft/program/article/vc/vc405.html学到的,

从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题,我的体会

特别是文字处理CEditView当产生多个视图类时,这个功能是非常需要的。

CDocument类提供了两个函数用于视图类的定位:

GetFirstViewPosition()和GetNextView()

virtual POSITION GetFirstViewPosition() const;

virtual CView* GetNextView(POSITION& rPosition) const;

注意:GetNextView()括号中的参数用的是引用方式,因此执行后值可能改变。

GetFirstViewPosition()用于返回第一个视图位置(返回的并非视图类指针,而是一

个POSITION类型值),GetNextView()有两个功能:返回下一个视图类的指针以及用

引用调用的方式来改变传入的POSITION类型参数的值。很明显,在Test程序中,只有

一个视图类,因此只需将这两个函数调用一次即可得到CTestView的指针如下(需定

义一个POSITION结构变量来辅助操作):

CTestView* pTestView;

POSITION pos=GetFirstViewPosition();

pTestView=GetNextView(pos);

这样,便可到了CTestView类的指针pTestView.执行完几句后,变量pos=NULL,因为没

有下一个视图类,自然也没有下一个视图类的POSITION.但是这几条语句太简单,不

具有太强的通用性和安全特征;当象前面说的那样,当要在多个视图为中返回某个指

定类的指针时,我们需要遍历所有视图类,直到找到指定类为止。判断一个类指针指

向的是否某个类的实例时,可用IsKindOf()成员函数时行检查,如:

pView->IsKindOf(RUNTIME_CLASS(CTestView));

即可检查pView所指是否是CTestView类。

有了以上基础,我们已经可以从文档类取得任何类的指针。为了方便,我们将其作

为一个文档类的成员函数,它有一个参数,表示要获得哪个类的指针。实现如下:

CView* CTestDoc::GetView(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.\r\n http://www.VCKBASE.com");
return NULL;

}

return pView;

}

其中用了两次视图类的成员函数IsKindOf()来判断,是因为退出while循环有三种

可能:

1.pos为NULL,即已经不存在下一个视图类供操作;

2.pView已符合要求。

1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图

的位置同时返回当前视图指针,因此pos是pView的下一个视图类的POSITION,完全

有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一

个视图类时就如引。因此需采用两次判断。

使用该函数应遵循如下格式(以取得CTestView指针为例):

CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));

RUNTIME_CLASS是一个宏,可以简单地理解它的作用:将类的名字转化为

CRuntimeClass为指针。至于强制类型转换也是为了安全特性考虑的,因为从同一个

基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要,但能避免一

些可能出现的麻烦。

3.从一个视图类取得另一视图类的指针 综合1和2,很容易得出视图类之间互相获得

指针的方法:就是用文档类作中转,先用1的方法得到文档类的指针,再用2的方法,

以文档类的视图定位函数取得另一个视图类。同样,可以实现成一个函数:

(假设要从CTest***iew中取得指向其它视图类的指针)

CView* CTest***iew::GetView(CRuntimeClass* pClass)

{

CTestDoc* pDoc=(CTestDoc*)GetDocument();

CView* pView;

POSITION pos=pDoc->GetFirstViewPosition();

while(pos!=NULL){

pView=pDoc->GetNextView(pos);

if(!pView->IsKindOf(pClass))

break;

}

if(!pView->IsKindOf(pClass)){

AfxMessageBox("Connt Locate the View.");

return NULL;

}

return pView;

}

这个函数和2中的GetView()相比,一是多了第一句以取得文档类指针,二是在

GetFirstViewPosition()和GetNextView()前加上了文档类指针,以表示它们是文档

类成员函数。有了此函数;当要从CTest***iew中取得CTestBView的指针时,只需如

下:CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));

11)对于单文档中也可以加入多个文档模板,但是一般的开发就使用MDI方式开发

多文档模板,其方法与上述视图的获取方法很接近,这里稍做解释,如果不清楚,

请查阅MSDN,(以下四个内容(11、12、13、14)来源:
http://sanjianxia.myrice.com/vc/vc45.htm)
可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板

的位置;利用该值来调用CWinApp::GetNextDocTemplate函数,获得第一个

CDocTemplate对象指针。 POSITION GetFirstDocTemplate( ) const;

CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;

第二个函数返回由pos 标识的文档模板。POSITION是MFC定义的一个用于迭代或对象

指针检索的值。通过这两个函数,应用程序可以遍历整个文档模板列表。如果被检索

的文档模板是模板列表中的最后一个,则pos参数被置为NULL。

12)一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文

档的指针列表。

用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一

个文档的位置,并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与

模板相关的文档列表。函数原形为:

viaual POSITION GetFirstDocPosition( ) const = 0;

visual CDocument *GetNextDoc(POSITION & rPos) const = 0;

如果列表为空,则rPos被置为NULL.

13)在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。

函数原形如下: CDocTemplate * GetDocTemplate ( ) const;

如果该文档不属于文档模板管理,则返回值为NULL。

14)一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。

CDocument::AddView将一个视连接到文档上,将该视加入到文档相联系的视的列表

中,并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或

Window/Split的命令而将一个新创建的视的对象连接到文档上时, MFC会自动调用

该函数,框架通过文档/视的结构将文档和视联系起来。当然,程序员也可以根据自

己的需要调用该函数。

Virtual POSITION GetFirstViewPosition( ) const;

Virtual CView * GetNextView( POSITION &rPosition) cosnt;

应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的

列表中的第一个视的位置,并调用CDocument::GetNextView返回指定位置的视,并将

rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个

视,则将rPosition置为NULL.

15)从一个视图类取得另一视图类的指针

这个应用在多视的应用程序中很多见,一般如果自己在主程序或者主框架中做好变

量记号,也可以获得,还有比较通用的就是用文档类作中转,以文档类的视图遍历

定位,取得另一个视图类。这个功能从本文第10项中可以得到。

————————————————————————————————————————————

--------------------------------------------------------------------------------

VC多文档程序结构[转]

2008-04-03 15:03

1、模板、文档、视图、框架的关系

  连载1~5我们各个击破地讲解了文档、文档模板、视图和框架类,连载1已经强调这些类有着亲密的内部联系,总结1~5我们可以概括其联系为:

  (1)文档保留该文档的视图列表和指向创建该文档的文档模板的指针;文档至少有一个相关联的视图,而视图只能与一个文档相关联。

  (2)视图保留指向其文档的指针,并被包含在其父框架窗口中;

  (3)文档框架窗口(即包含视图的mdi子窗口)保留指向其当前活动视图的指针;

  (4)文档模板保留其已打开文档的列表,维护框架窗口、文档及视图的映射;

  (5)应用程序保留其文档模板的列表。

  我们可以通过一组函数让这些类之间相互可访问,表6-1给出这些函数。

  表6-1 文档、文档模板、视图和框架类的互相访问

--------------------------------------------------------------------------------

调用全局函数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、应用程序对象有一个文档模板管理器CDocManager* m_pDocManager(第一次调用AddDocTemplate时new出来)

2、文档模板管理器有一个文档模板对象列表CPtrList m_templateList(AddDocTemplate 函数负责添加该列表)

3、文档模板对象拥有文档、视图、框架的静态CRuntimeClass成员指针用于动态创建,还有一个m_nIDResource用来表示应采用的UI对象

4、每个文档模板对象拥有 m_pOnlyDoc 或 m_docList (文档指针或文档指针列表),OnFileNew 和 OnFileOpen都调用文档模板对象的OpenDocumentFile,OpenDocumentFile
调用文档模板的 CreateNewDocument,CreateNewDocument再调用文档模板的 AddDocument 填充该文档列表或文档指针

5、文档对象有一个文档模板指针 m_pDocTemplate (回指文档对象所属模板对象).同上,也是文档模板的 AddDocument 成员函数把 this 指针(文档模板自身).塞给刚刚创建的文档对象

6、文档对象有一个 m_viewList(视图列表),OnFileNew 和 OnFileOpen 都调用文档模板对象的OpenDocumentFile,该函数调用 CreateNewDocument 创建文档,然后调用 CreateNewFrame
创建框架对象.

 CreateNewFrame 构造CCreateContext对象

 CCreateContext两个重要字段:(1)刚创建的文档指针(2)视图的CRuntimeClass指针

 CreateNewFrame 创建框架对象后由该对象调用 LoadFrame

 LoadFrame 的最后一个参数即为 CCreateContext 指针

 LoadFrame 调用 Create,Create 再调用 CreateEx 最后一个参数均为此CCreateContext指针

 Create的调用由消息映射表引发CFrameWnd::OnCreate被调用

 OnCreate的LPCREATESTRUCT的一个字段lpCreateParams 仍然是这个CCreateContext指针

 则在CFrame::OnCreate中,由这个CCreateContext的CRuntimeClass(视图的)来调用CreateObject

 产生视图对象后,由该对象调用Create(最后一个参数仍然是这个CCreateContext指针)

 视图对象的Create由消息映射表引发视图对象的OnCreate被调用

 视图的OnCreate的参数 LPCREATESTRUCT 的 lpCreateParams 还是这个CCreateContext指针)

 于是利用 CCreateContext 的成员 m_pCurrentDoc (当前文档)

 来调用 CDocument::AddView 把视图加入文档的视图列表

7、视图有一个文档指针m_pDocument (指向所属文档)

 同上,也是CDocument::AddView函数初始化的,如下所示:

 pView->m_pDocument = this;

8、框架有一个m_pViewActive(活动视图)

 由框架的SetActiveView进行设置
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: