zoukankan      html  css  js  c++  java
  • 【转】MFC 多文档

    2010-01-11 17:23
    如何在MFC单文档中创建多视图

    基本步骤如下:

    1.首先创建一个MFC单文档应用程序。

    2.添加4个MFC类TopLView、BottomLView、TopRView、BottomRView,基类为CView。

    3.添加一个MFC类CControlForm,基类为CFormView,对话框ID默认。

    4.创建一个切分类,如MySplitter,基类为CSplitterWnd(默认基类选项中无此类,自己添加即可)。

    5.在框架类Cmainframe的头文件中,添加2个MySplitter的变量(因为下面要进行两次切分操作)。

    6.重写框架类Cmainframe的OnCreateClient函数,如下:

    //第一次静态切分CreateStatic,一行两列

    if (!m_wndSplitter.CreateStatic(this,1,2))

       return FALSE;

    //第二次静态切分(将第一次切分后的第二列再分为2*2)及所有的子视图创建(CreateView函数)。

    if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CControlForm), CSize(100, 100), pContext) ||
       !m_wndSplitter2.CreateStatic(&m_wndSplitter,2,2,WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0, 1))||  !m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(TopLView), CSize(350, 240), pContext) ||
       !m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(BottomLView), CSize(350, 240), pContext) ||
       !m_wndSplitter2.CreateView(0, 1, RUNTIME_CLASS(TopRView), CSize(350, 240), pContext) ||
       !m_wndSplitter2.CreateView(1, 1, RUNTIME_CLASS(BottomRView), CSize(350, 240), pContext))
    {
       m_wndSplitter.DestroyWindow();
       return FALSE;
    }

    // return CFrameWnd::OnCreateClient(lpcs, pContext);      //注释掉原有的响应函数

    注意:记得在Mainfrm.h中添加以上五个视图类的头文件:

    #include "CControlForm.h"
    #include "TopLView.h"
    #include "TopRView.h"
    #include "BottomLView.h"
    #include "BottomRView.h"

    6. 切分视图完成,结果如下:


    其中,最左的视图为FormView类型,操作类似对话框(可以在Resource-Dialog看到其对应的对话框资源);右边四个的操作则类似普通视图。

    补充内容:

    a. 此时创建的各个子视图之间的分割条可以拖动,以改变视图其大小。如果想固定分割条,则需要重载MySplitter类的鼠标响应函数。可以通过一个Bool型变量来控制是否可以拖动分割条:

    if (Isvisable) //Isvisable在构造函数中已被初始为FALSE
    {
       CSplitterWnd::OnLButtonDown(nFlags, point);
    }

    b. 还可以通过重载MySplitter类的OnDrawSplitter函数来改变分割条的样式。以下为该函数代码:

    #define LP RGB(128,128,128)
    #define RB RGB(192,192,192)

    //如果pDC 为 NULL则仅使分割窗口区域无效
    if (pDC == NULL)
    {
       RedrawWindow(rect, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
       return;
    }
    ASSERT_VALID(pDC);

    CRect rc = rect;

    switch(nType)
    {
    case splitBorder:
      //重画分割窗口边界
       pDC->Draw3dRect(rc,LP,LP);
       rc.InflateRect(-1,-1);
       pDC->Draw3dRect(rc,RB,RB);
       return;
    case splitBox:
       pDC->Draw3dRect(rc,LP,LP);
       rc.InflateRect(-1,-1);
       pDC->Draw3dRect(rc,LP,LP);
       rc.InflateRect(-1,-1);
       pDC->FillSolidRect(rc,RGB(128,128,128));
       pDC->Draw3dRect(rc,RB,RB);
       return;
    case splitBar:
       //重画分割条
       pDC->FillSolidRect(rc,RGB(192,192,192));
       rc.InflateRect(-1,-1);
       pDC->Draw3dRect(rc,RB,RB); 
       return;
    default:
       ASSERT(FALSE);
    }
    //填充中间的部分
    pDC->Draw3dRect(rect, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNHIGHLIGHT));

    http://hi.baidu.com/mplsfec/blog/item/025b1c63d939fad4e7113ad4.html

    http://hi.baidu.com/wang_qingyuan/blog/item/60870400275c5b087bec2cbd.html

    深入分析MFC文档视图结构
    2008-10-16 19:40
    文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer模式的具体实现框架之一,Document/View Architecture通过将数据和其表示分开,提供了很好的数据层次和表现层次的解耦。然而,虽然我们使用MFC AppWizard就可以很轻松地获得一个支持Document/View Architecture的MFC程序框架,Document/View Architecture本身的复杂性加上VC产生的一系列代码足够让我们眼花缭乱,一时陷入云里雾里不可自拔。加上我们更多的人都没有经过Windows SDK Programming 的学习和经历就直接进行MFC Programming的学习和开发,更是面对一堆的代码不知所措。

    之于Document/View Architecture,侯捷先生的《深入浅出MFC》一书确实进行了很深入的分析和研究,网络上也有很多在侯捷先生著述的基础上的进一步的文章出现,但是个人觉得这里面有一点瑕疵(仅代表k_eckel浅见):太过深入,这些分析和研究都最终会定位到Windows SDK中窗口的创建过程、MFC中对Document/View Architecture支持所提供的复杂无序的宏等对于没有Windows SDK Programming 经验和经历的学习者和对于MFC不是很熟悉的学习者无异于是徒增烦恼,一个本来就很复杂的问题更加地复杂化了。我的观点是这个过程是必要的,然而不是每个人所必需的,或者说不是每个人在初期学习和绝大多数项目开发中所必需的。我向来对众多的仅仅学会了拖拉点拽就以为会了MFC(侯捷先生在《深入浅出MFC》一书中对这个群体有一个照面,这里不罗嗦)不以为然,但是我依然认为轻量级学习成本是重要的,容易上手,易于接受是一门技术成功或者说有价值的一个很大的决定性因素。因此提供一个轻量级的学习过程对于学习来说是很有必要性的,本系列文章就遵循这样一个理念,对MFC中Document/View Architecture进行一个分析(姑且也可以称之为深入),尽量将对Document/View Architecture的理论研究(侯捷先生书中很多内容)和实际的项目开发结合起来,最后提供一个简单但是全面的Document/View Architecture项目开发(主要是界面框架设计和开发)的实际例子,供参考。

    1 必备基础知识概述
    1.1 MFC文档视图结构程序结构总揽
    当我们使用MFC AppWizard生成一个MFC程序,选用所有默认的设置(当然也是Multiple Documents,本文讨论主要基于Multiple Documents,对于Single Document情况仅以简单表述提及,皆因后者和前者很多相似相同之处,但前者更为复杂,并且更加常用。),假设你的程序名称为A ,则你会得到CMainFrame、CChildFrame、CAboutDlg、CADoc、CAView、CAApp 6个类(Single Document 仅少一个CChildFrame类,其余均同)。这些类的具体含义将在后面给出,这里先要给出一个MFC 支持文档视图结构程序(以下简称App)的主要组成:

    u        一个App(对应类CAApp)可以包含多个文档模版(CDocTemplate),但是MFC AppWizard(无论是SDI还是MDI)都只是默认生成一个。但是在实际开发中一个文档模版不够,需要自己手工添加(在后面实际项目例子提供示例)。这个结构是通过MFC中CWinApp的成员变量CDocManager* m_pDocManager实现的,我们的CAApp正是继承自MFC提供的CWinApp类。

    u        CDocManager类则拥有一个指针链表CPtrList m_templateList来维护这些文档模版。这些文档模版都是在CAApp::InitInstance()中通过AddDocTemplate(pDocTemplate)。

    u        CDocTemplate拥有3个成员变量,分别保存着Document、View、Frame的CRuntimeClass指针,另外持有成员变量m_nIDResource,用来指定这个Document显示时候采用的菜单资源。这4份数据都在CAApp::InitInstance()中CDocTemplate的构造函数中指定。在Document中拥有一个回指CDocTemplate的指针(m_pDocTemplate)。

    u        一个文档可以有多个视图,由Document中成员变量CPtrList m_ViewList维护。

    u        CFrameWnd拥有一个成员变量CView* m_pActiveView指向当前活动的View。

    u        CView中拥有一个成员变量CDocument* m_pDocument指向该视图相关的Document。

    [注解]:①MFC SDI/MDI程序默认都默认生成了一个文档模版,并将这个文档模版Add到其文档模版的链表中,由于这是MFC默认提供的,因此这个文档模版会被插入到文档模版的第一个位置,而MFC也是通过这个文档模版的特定位置可以确定的。默认情况下,当我们点击File(Open)/ File(New)的时候,这个文档模版会被启用。

              除了侯捷先生在《深入浅出MFC中列出的以上的深入分析,我们还应该(很大程度上更加重要)掌握以下的关于MFC SDI/MDI的知识:

    u        文档的本质:文档是用来保存数据以及关于数据的处理的,每当MFC SDI/MDI响应File(Open)/ File(New)的时候都会打开一份文档。文档可以拥有多个视图。文档和视图的关系可以这样理解:文档是被视图观察的对象。

    u        视图本质:视图在Windows中就是一个窗口,也就是一个可视化的矩形区域。视图是用来表示文档的数据的。但是每个视图必需依附于一个框架(SDI中是MainFrame,MDI是ChildFrame)。当然你可以自己去Create一个视图,并且去显示它。

    u        框架的本质:框架实际是也是一个Windows窗口。但是在框架上可以放置菜单、工具栏、状态栏等。而视图则放在框架的客户区。因此MFC中我们看到的窗口实际上Frame和View共同作用的结果。

    u        在某一时刻,程序中只有一个活动的文档、框架和视图,即当前的文档、框架、视图。

    1.2 MFC SDI/MDI各个类之间的互访
            在实际项目开发中用的最多就是各个类之间的互访问,这里将网络上和书籍中提到的做了一个总结,也是笔者在实际开发中都用到过的。

            访问对象
    访问位置
    访问实现

    应用程序App
    任何位置
    ①      AfxGetApp();

    ②      在要使用应用程序App的文件中加入:

    extern CAApp theApp,然后直接使用全局的theApp变量。

    主框架窗口
    任何位置
    ①AfxGetMainWnd();

    ②AfxGetApp()->m_pMainWnd;

    视图
    框架类中
    GetActiveView();   //当前的活动视图

    文档类中
    GetFirstViewPosition();//可以获取全部视图

    GetNextView();

    文档
    文档类中
    GetDocument();

    文当模版类中
    GetFirstDocPosition(); //该文档模版对应全部文档

    GetNextDoc();

    框架类中
    GetActiveDocument(); //当前活动文当

    子框架类(MDI中)
    主框架类中
    ①MDIGetActive();

    ②GetActiveFrame();

    视图类中
    GetParentFrame();

    文档模版
    文档类中
    GetDocTemplate();

    应用程序App中
    GetFirstDocTemplatePosition();

    GetNextDocTemplate();


            说明:1)以上给出的都是方法,实际访问中可能还要进行以下简单的处理,如类型转换,循环遍历等;

                     2)可能没有列举完所有可能位置的互访问,但可以通过他们的组合得到。

    2 文档、视图、框架之间的关联
            MFC SDI/MDI中的核心就在于文档、视图、框架之间的关联,形成了一个有机的可运作的整体。MFC提供了默认的关联关系,但是在实际的项目开发中很多时候需要动态进行他们的之间的关联。

    2.1 文档和视图间的关联
            使用MFC AppWizard声称MFC SDI/MDI程序,在App类的InitInstance()方法中有如下代码(假设Project名称均为Test):

    u        SDI中

    CSingleDocTemplate* pDocTemplate;

    pDocTemplate = new CSingleDocTemplate(

                   IDR_MAINFRAME,

                   RUNTIME_CLASS(CTestDoc),

                   RUNTIME_CLASS(CMainFrame),        // main SDI frame window

    RUNTIME_CLASS(CTestView));

            AddDocTemplate(pDocTemplate);


    u        MDI中

    CMultiDocTemplate* pDocTemplate;

    pDocTemplate = new CMultiDocTemplate(

                   IDR_TESTTYPE,

                   RUNTIME_CLASS(CTestDoc),

                   RUNTIME_CLASS(CChildFrame), // custom MDI child frame

                   RUNTIME_CLASS(CTestView));

            AddDocTemplate(pDocTemplate);


    这里通过CDocTemplate(无论是SDI中的CSingleDocTemplate还是MDI中的CMultiDocTemplate)的构造函数,将文当、视图和框架(SDI中与主框架,MDI中与自框架)关联在一起了,形成了一个整体。

    手工实现文当和视图的关联

    在实际的项目开发时候仅仅依靠MFC AppWizard生成的文当和视图、框架是不够的,因此我们需要掌握手工进行这种关联。手工进行文当和视图的关联可以有以下两种实现方式:

    l          模仿MFC AppWizard实现,使用CDocTemplate的构造函数:在上面的分

    析中我们可以看到通过CDocTemplate(无论是SDI中的CSingleDocTemplate还是MDI中的CMultiDocTemplate)的构造函数我们可以获得文档、视图和框架的关联。因此可以通过模拟这种方式进行关联。具体实现方法如下:

    1)   创建新的文档、视图和框架类,方法是使用VC中的Insert MFC Class

    实现。注意到框架类选择CMDIChildWnd作为基类,文档类选择CDocument作为基类,而视图类则可以根据需要选择CView或其子类(CEditView)等作为基类。

    2)   为该框架添加菜单资源,方法是在VC资源窗口Menu菜单下添加新的菜

    单,当然可以通过复制VC提供默认菜单进行修改。

    3)   在App类的InitInstance()中添加如下类似代码:

    CMultiDocTemplate* m_pDocTemplate;

    m_pDocTemplate = new CMultiDocTemplate(

                   IDR_TESTTYPE,                //改为你新建的菜单资源ID

                   RUNTIME_CLASS(CTestDoc),    //改为你新建的文档类

                   RUNTIME_CLASS(CChildFrame), //改为你新建的框架类

                   RUNTIME_CLASS(CTestView));   //改为你新建的视图类

            AddDocTemplate(m_pDocTemplate);


    4)   为了记录这个文档模版,你可以在App类中添加一个CMultiDocTemplate*

    类型变量来维持这个文档模版。

    l          上面给出了通过CDocTemplate的构造函数将文档、视图、和框架关联起来,但

    是有时候我们并不想创建一个新的文档模版,我们只是想给同一个数据提供不同的结果显示,或者说是为同一个文档添加一个新的视图,并提供他们之间的一个切换。我在《VC项目开发之单文档多视图实现》一文给出了这样的一个实现。还有一种可能就是我们本来不是一个文档视图结构支持的程序,想为视图添加一个文档,更好进行业务逻辑和表示层的一个分离。因此我们给出了第二种视图和文档关联的方法:我们使用CCreateContext类进行他们之间的关联,具体实现为:

            m_pAnotherView = new CAnotherView(); //new 一个新的视图,可以改为你新建的视图

        

         //获取一个已有的文档,可以是你新建的文档

            CDocument* m_pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();

           

    //文档和视图关联

    CCreateContext context;

            context.m_pCurrentDoc = m_pDoc;

            //创建视图

            UINT m_IDFORANOTHERVIEW = AFX_IDW_PANE_FIRST + 1; //创建视图的ID号,你可以自己设置

            CRect rect;

            m_pAnotherView->Create(NULL,NULL,WS_CHILD,rect,m_pMainWnd,m_IDFORANOTHERVIEW,&context);


    l          在框架和视图关联的时候进行设置,具体见一下框架和视图关联部分。

    2.2 框架和视图的关联
            在第一部分分析我们知道,框架和视图其实都是windows窗口,不过框架提供了菜单、标题栏、状态栏等资源,而视图则只是一个矩形区域。MFC程序中视图决定大多数时候要依附于一个框架(SDI中的MainFrame和MDI中的子框架窗口),可以这样理解,框架相当于一个窗口容器(当然它本身也是一个windows窗口),而视图则正好是放置在框架内客户区域的内容。

            框架和视图的关联也可以通过模仿MFC AppWizard实现,使用CDocTemplate的构造函数实现,即和2.1中文档和视图间的关联方式相同,这里就不再给出,参看上面的详细实现即可。

            同上面的分析,在很多的时候我们并不是需要提供一个新的文档模版,我们只是需要显示一个新的窗口(MDI程序),例如我们在作MIS系统界面管理的时候,经常出现的情况就是用户点击一个菜单选项,即弹出一个处理窗口。而要显示一个新的窗口,我们可以通过我在《VC 多文档用户界面设计》一文中给出的方法(通过CDocTemplate的OpenDocumentFile()方法打开一个文档实现),这样就建立一套的文档、视图和框架的体系。上面已经分析到,我们看到MFC的窗口实际上框架和视图的一个结合体,我们并不一定要提供文档、视图、框架的整个体系,我们只需要框架和视图的结合即可实现窗口的显示,这就要经过两个步骤实现:第一步将视图和框架关联,第二步显示框架(也就是一个windows窗口的显示)。以下给出框架和视图关联的具体实现:

            CChildFrame* pFrm = new CChildFrame();    //框架可以是你新建或者定制的框架类

            CCreateContext context;

            context.m_pNewViewClass = RUNTIME_CLASS(CDemoView);   //视图可以是你想显示的视图

            pFrm->LoadFrame(IDR_TEST2TYPE,WS_CHILD |

    WS_OVERLAPPEDWINDOW,this,&context);   //菜单资源你可以修改

            pFrm->ShowWindow(SW_SHOW);            //显示窗口

            pFrm->InitialUpdateFrame(NULL,true);         //调用视图的OnInitialUpdate()和框架的ActiveFrame(),你可以在这里设置窗口的标题


            当然你可以在这里添加视图和文档的关联,具体实现是添加以下代码:

    context.m_pCurrentDoc = m_pDoc;    // m_pDoc就是你要关联到的文档对象
     


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhangyinze123/archive/2010/02/04/5289268.aspx

  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/superanyi/p/1990765.html
Copyright © 2011-2022 走看看