• VC切分窗口和多视图


    动态切分窗口:

    动态切分窗口不能包含多于4个的窗格,要想得到4个以上的窗格,可以使用静态切分窗口。动态切分窗口中的几个窗格通常使用的是同一个视图类。

    创建动态切分窗口的方式共有3种:

    1、在创建应用程序时,利用应用程序向导AppWizard的选项设置切分窗口

    2、在创建了应用程序之后,通过添加组件对窗口进行切分

    3、通过手动添加代码编程的方式

    使用AppWizard创建动态切分:

    在MFC AppWizard Step 4 of 6对话框中,单击Advanced按钮,弹出Advanced Options对话框,选择Window Styles选项卡,选中该页的Use split window检查框。

    使用Splitter Bar组件:

    选择Project|Add To Project|Components and Controls...菜单,弹出Components and Controls Gallery对话框。双击Visual C++ Components目录,选择Splitter Bar项,插入Splitter Bar组件。

    运行程序,打开【查看】菜单或者是【窗口】菜单,找不到前面使用AppWizard添加动态切分时的【分隔】菜单项。说明Splitter Bar组件的方式并没有添加相应的菜单项,程序员可以自己添加上去。

    注意:菜单的Caption(标题)可以随便设定,但注意菜单项的ID必须是ID_WINDOW_SPLIT。ID_WINDOW_SPLIT是系统预先指定的,程序员一般不需要对此命令ID添加命令消息处理函数,就可以实现分隔,因为MFC应用程序框架中已经对该命令ID的消息进行了处理。

    手动添加代码:

    1、在框架窗口类(对单文档为主框架窗口,对多文档为子框架窗口)中声明一个CSplitterWnd类的成员变量m_wndSplitter

    2、使用ClassWizard为框架窗口类添加OnCreateClient函数

    注意:这里使用ClassWizard是重写父类的虚函数,而不是添加消息处理

    3、在OnCreateClient函数中调用CSplitterWnd类的成员函数Create产生动态切分

    4、为应用程序添加一个ID为ID_WINDOW_SPLIT的菜单项

    CSplitterWnd切分窗口类:

    CSplitterWnd的成员函数中,有3个使用非常频繁

    1、Create函数

    创建一个动态的切分窗口

    2、CreateStatic函数

    创建一个静态的切分窗口

    3、CreateView函数

    为静态切分窗口创建视图窗口。在框架显示一个静态切分窗口之前,该窗口的所有视图窗格都必须已被创建好。当动态切分窗口时,此函数被框架窗口自动调用。

    静态切分窗口:

    静态切分窗口是指在窗口创建时,切分窗口的窗格就已经创建好了,且窗格的数量和顺序不会改变。最多可以支持16行×16列的窗口(即256个窗格),但是必须在应用程序中创建窗格,而且不同的窗口往往使用不同的视图类。

    创建静态切分的步骤:

    1、在框架窗口类中声明一个CSplitterWnd类的成员变量m_wndSplitter

    2、使用ClassWizard为框架窗口类添加OnCreateClient函数

    3、在OnCreateClient函数中调用CSplitterWnd::CreateStatic产生静态切分

    4、在OnCreateClient函数中调用CSplitterWnd::CreateView产生每个切分的视图窗口

    为2DCAD应用程序添加静态切分功能:

    1、声明切分窗口类对象m_wndSplitter

    为主框架窗口类CMainFrame添加保护成员变量m_wndSplitter,代码如下:

    CSplitterWnd m_wndSplitter; //用于产生静态切分

    2、在框架窗口类中添加OnCreateClient函数

    打开ClassWizard,选中MessageMaps选项卡,在Class name中选择CMainFrame类,在ObjectIDs列表中选择CMainFrame,在Message列表框中双击OnCreateClient项,为框架窗口添加OnCreateClient函数。

    3、使用CreateStatic产生静态切分

    在OnCreateClient函数中添加如下代码,就可以产生1×2的静态切分窗口:

    m_wndSplitter.CreateStatic(this, 1, 2);

    4、使用CreateView产生每个视图窗口

    当用户建立一静态切分窗口时,应当同时建立窗口内的所以区域。可以在OnCreateClient函数中添加如下代码来为第一行第一列的窗格产生视图:

    m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CMy2DCADView),

    CSize(450, 250), pContext);

    其中,第3个参数,视图类的执行期类CRuntimeClass指针,可以用宏RUNTIME_CLASS来获得。

    注意:(1)必须为每一个静态切分窗口创建视图窗口,不能漏掉一个

    (2)由于使用到了视图类,因此,必须包含相应的类的头文件。在MainFrm.cpp文件的开始部分包括以下两个头文件:

    #include "2DCADDoc.h"
    #include "2DCADView.h"

    (3)产生静态切分后,就不能再调用默认情况下的基类的OnCreateClient函数。因此,应该将下面的代码删除或者注释掉:

    // return CFrameWnd::OnCreateClient(lpcs, pContext);

    最后,完整的CMainFrame::OnCreateClient函数代码如下:

    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
    // TODO: Add your specialized code here and/or call the base class
    //使用CreateStatic函数产生静态切分
    m_wndSplitter.CreateStatic(this, //父窗口指针
    1, //行数
    2); //列数

    //使用CreateView为第1个窗格产生视图
    m_wndSplitter.CreateView(0, 0, //窗格的行、列序数
    RUNTIME_CLASS(CMy2DCADView), //视图类
    CSize(450, 250), //初始化大小
    pContext); //父窗口的创建参数

    //使用CreateView为第2个窗格产生视图
    m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMy2DCADView),
    CSize(450, 250), pContext);

    return 1; //不再调用基类的OnCreateClient函数
    // return CFrameWnd::OnCreateClient(lpcs, pContext);
    }

    这时,用户在一个视图中所作的修改还不能立刻反映到其他视图窗口中,还应添加相应的通知视图重画的代码。

    5、通知视图重画

    文档类有一个名为UpdateAllViews的函数,可以在文档数据发生改变时通知所有的视图窗口重画。

    在视图类的OnLButtonDown函数中每个调用SetModifiedFlag函数的后面立即调用UpdateAllViews的函数,代码如下:

    ...

    pDoc->SetModifiedFlag(); //设置文档“脏”标志
    pDoc->UpdateAllViews(this); //重画所有视图

    ...

    向当前工程中插入新类的两种方式:

    1、使用New Class对话框添加新类

    (1)MFC ClassWizard中的New Class对话框

    使用ClassWizard对话框中的Add Class...按钮下的New...菜单项可以打开MFC ClassWizard对话框下的New Class对话框。这个对话框用来向当前工程中添加派生自MFC类库的新类。

    (2)通用的New Class对话框

    单击菜单命令Insert|New Class...可以打开一个通用的New Class对话框。实际上通用的New Class对话框相当于包含了3个对话框,用于产生几乎所有不同的类。

    2、使用插入包含类定义的文件到当前工程中

    (1)将所需类的.h、.cpp文件复制到目标工程目录下

    (2)打开目标工程,单击Project|Add To Project|Files...菜单项插入所需类的.h、cpp文件到目标工程中

    (3)在所需类的.cpp文件中,去掉包含原来的工程的头文件语句(比如2DCAD.h),添加包含目标工程的头文件语句(比如Mut.h)

    添加新的视图类:

    为2DCAD工程添加一个新的视图类CTextView,单击Insert|New Class...菜单项,在New Class对话框中确保Class type中选择的是MFC Class,在Name编辑框中输入CTextView,在Base class下拉列表中指定基类为CEditView。

    添加了新的视图类之后,就可以在框架窗口的OnCreateClient函数中调用CreateView函数时使用这个新视图类了。接下来使用CTextView作为静态切分窗口中第二个窗格的视图类,在OnCreateClient函数中修改创建第二个窗口视图的代码如下:

    //使用CreateView为第2个窗格产生视图
    m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CTextView),//使用文本视图类
    CSize(250, 250), pContext);

    由于使用到了新的视图类,因此,应该在MainFrm.cpp文件的开始部分添加包含CTextView类头文件的代码:

    #include "TextView.h"

    注意:CEditView封装了编辑框的功能,因此,如果要编写文字处理软件,可以使用CEditView作为视图基类。CEditView最多支持64K的文本,如果需要支持更丰富的文本,可以使用CRichEditView作为视图基类,但要包含头文件afxrich.h。

    表单视图类CFormView:

    CFormView就是可以在其中包含许多控件的视图基类。这个类也像CDialog对话框类一样,封装了数据交换功能。甚至可以将CFormView理解为作为视图的对话框。

    1、创建对话框模板资源

    (1)添加对话框模板,ID为IDD_FORMVIEW

    (2)修改属性

    在Style选项卡中,设置Style选项为Child,Border选项为None,并去掉对Title Bar复选框的勾选。

    注意:由于视图类是一个子窗口,因此,必须设置Child选择,否则程序不能正常运行。

    (3)添加控件

    删掉默认的OK和Cancel按钮,依次添加一个静态文本、一个分组框和4个单选按钮,同时为第一个单选按钮添加上Group属性。

    注意:对一组单选按钮来说,只需要对该组的第一个单选按钮设置Group属性就可以了。如果不设置Group属性,就无法添加对应的成员变量。

    2、产生CFormView的派生类

    (1)使用ClassWizard为IDD_FORMVIEW对话框模板资源添加一个名为CColorForm的视图类,注意选择基类为CFormView

    (2)在Member Variables选项卡中为IDC_RADIO1添加一个名为m_nColor的整型成员变量

    注意:对一组单选按钮只能对带有Group属性的按钮增加一个成员变量,并且这个成员变量必须是int型。0表示选择第一个,依次类推,-1表示未选择。

    在CColorForm构造函数中令成员变量m_nColor的初始值为0,表示选择第一项。

    3、修改切分窗口的视图类

    打开OnCreateClient函数,修改创建第二个窗口视图的代码如下:

    //使用CreateView为第2个窗格产生视图
    m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CColorForm),//使用表单视图类
    CSize(250, 250), pContext);

    由于使用到了新的视图类,因此,应该在MainFrm.cpp文件的开始部分添加包含CColorForm类头文件的代码:

    #include "ColorForm.h"

    可以像处理无模式对话框那样,在表单视图类中添加相应的消息处理函数。

    一个多文档多视图的综合示例:

    下面综合前面的知识,创建一个包含多文档、多视图、动态切分、三叉静态切分以及可以支持多种文档类型的综合示例。

    支持多种文档类型:

    在MFC应用程序中,要增加附加的文档类型,大致可分为以下几步:

    1、使用ClassWizard添加新的文档类、子框架窗口类以及视图类(如果需要的话)

    2、利用资源编辑器为新的文档类型添加字符串资源

    3、利用资源编辑器添加附加的图标和菜单资源

    4、创建新的文档模板对象并加入到应用程序中

    5、完成文档的序列化以及视图的显示交互工作

    下面为Mut添加支持多文档类型的功能(此时Mut本身是一个空的具有动态切分窗口的多文档程序):

    1、添加新的文档类、子框架窗口类和视图类

    一般来说,一个新的文档类型所需要的文档类、外边框窗口类和视图类有可能都不同于已经存在的类的,但也可能和现存的类相同(比如使用相同的子框架窗口)。因此,根据不同的需要会添加不同的类。这里,首先只添加一个新的视图类和子框架窗口类,而文档类则使用原来的类。

    注意:多种文档类型的各个文档类一般是不同的

    (1)添加新的视图类的方法可以参加《向当先工程中插入新类的两种方式》中的第二种方式,插入2DCAD程序中所用到的可以输入简单的文本的CTextView类。

    (2)添加新的子框架窗口类CTextFrame,基类选择为CMDIChildWnd。具体方法参加向当先工程中插入新类的两种方式》中的第一种方式。

    2、利用资源编辑器为新的文档类型添加字符串资源

    参照Mut应用程序已经存在的文档模板字符串资源IDR_MUTTYPE,在字符串编辑器中增加一个新的字符串资源,指定ID为IDR_TEXTTYPE,内容为:

    \nText\n文本视图窗口\nText Files(*.txt)\n.txt\nTextDocument\nText Document

    可见文档模板字符串包含7个由“\n”结尾并分隔的子串,最后一个字符串后面不需要“\n”。这些子串描述了文档的类型,它们的含义按照顺序分别如下:

    (1)窗口标题(2)文档名(3)新建文档类型名(4)过滤器名(5)文件扩展名(6)文档类型ID(7)注册文档类型名

    3、利用资源编辑器添加附加的图标和菜单资源

    (1)添加一个ID为IDR_TEXTTYPE的图标,可以利用画图工具编辑之

    (2)添加一个ID为IDR_TEXTTYPE的菜单,将IDR_MUTTYPE菜单资源下的【文件】、【编辑】、【查看】、【帮助】菜单复制到IDR_TEXTTYPE中。注意:可以使用右键菜单中的Insert Copy...,然后再修改。

    注意:这些资源的ID必须同第二步中创建文档模板字符串中所用的ID相同。

    4、创建新的文档模板对象并加入到应用程序中

    在应用程序类CMutApp的InitInstance函数中,参照应用程序框架生成的代码,创建另一个CMultiDocTemplate对象,并用CWinApp::AddDocTemplate成员函数注册该模板对象。

    //这是应用程序框架生成的代码
    CMultiDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(
    IDR_MUTTYPE,
    RUNTIME_CLASS(CMutDoc),
    RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    RUNTIME_CLASS(CMutView));
    AddDocTemplate(pDocTemplate);

    //创建新的文档模板对象
    pDocTemplate = new CMultiDocTemplate(
    IDR_TEXTTYPE, //新创建的字符串资源、图标资源和菜单资源
    RUNTIME_CLASS(CMutDoc), //仍旧使用原来的文档类
    RUNTIME_CLASS(CTextFrame), //新添加的子框架窗口类
    RUNTIME_CLASS(CTextView)); //新添加的文本视图类
    //将新的文档模板对象加入到应用程序中。
    AddDocTemplate(pDocTemplate);

    由于使用到了新的视图类CTextView和新的子框架窗口类CTextFrame,因此应该在Mut.cpp文件的开始部分包含它们的头文件:

    #include "TextView.h"
    #include "TextFrame.h"

    注意:此时Mut程序就包含有两个文档模板对象,可以支持两种不同的文档了,但是,它们使用了相同的文档类,而实际应用中应该使用不同的文档类。

    5、完成文档的序列化以及视图的显示交互工作

    最后,根据用户的需要,可以为文档类添加上数据保存以及序列化功能,为视图类添加相应的显示数据和交换功能。

    多文档的三叉静态切分:

    这三个窗口的排列方式类似“|—”形状,所使用的视图类分别类似前面2DCAD工程中创建的CColorForm类以及Mut工程中创建的CTextView类和CMutView类。

    1、添加新的文档模板对象

    (1)添加新的视图类和子框架窗口类

    在Mut工程中创建一个和2DCAD工程中相同的CFormView类的派生类CColorForm。

    注意:可以使用文件复制再插入的方法,还需要将所需的对话框资源模板以及控件的ID值定义都复制过来。

    再添加一个派生自CMDIChildWnd类的CThreeFrame类,作为文档的外边框窗口。

    (2)编辑资源

    添加ID都为IDR_THREETYPE的三个资源,字符串资源,图标资源和菜单资源。其中,字符串资源如下:

    \nThree\n三叉切分窗口\nThree Files(*.thr)\n.txt\nThreeDocument\nThree Document

    (3)创建新的文档模板对象

    在应用程序类CMutApp的InitInstance函数中,参照应用程序框架生成的代码,创建另一个CMultiDocTemplate对象,并用CWinApp::AddDocTemplate成员函数注册该模板对象。

    //创建三叉静态切分的文档模板对象
    pDocTemplate = new CMultiDocTemplate(
    IDR_THREETYPE, //用于三叉静态切分窗口的字符串资源、图标资源和菜单资源
    RUNTIME_CLASS(CMutDoc), //仍旧使用原来的文档类
    RUNTIME_CLASS(CThreeFrame), //新添加的三叉切分子框架窗口类
    RUNTIME_CLASS(CColorForm)); //新添加的表单视图派生类
    //将新的文档模板对象加入到应用程序中。
    AddDocTemplate(pDocTemplate);

    由于使用到了新的视图类CColorForm和新的子框架窗口类CThreeFrame,因此应该在Mut.cpp文件的开始部分包含它们的头文件:

    #include "ColorForm.h"
    #include "ThreeFrame.h"

    2、添加三叉静态切分

    (1)在子框架窗口类CThreeFrame中添加两个CSplitterWnd类的保护成员变量m_wndSplitter1和m_wndSplitter2,分别用于产生第一次静态切分和第二次静态切分。

    (2)使用ClassWizard为CThreeFrame添加OnCreateClient成员函数。

    (3)改写OnCreateClient成员函数代码如下:

    BOOL CThreeFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
    // TODO: Add your specialized code here and/or call the base class

    //使用CreateStatic函数产生第一次静态切分
    m_wndSplitter1.CreateStatic(this, //父窗口指针
    1, //行数
    2); //列数,一行两列

    //使用CreateView为第1个窗格产生CColorForm视图
    m_wndSplitter1.CreateView(0, 0, //窗格的行、列序数
    RUNTIME_CLASS(CColorForm), //表单视图类
    CSize(250, 250), //初始化大小
    pContext); //父窗口的创建参数

    //再次使用CreateStatic函数对第一次切分产生的第二个窗口静态切分
    m_wndSplitter2.CreateStatic(
    &m_wndSplitter1, //父窗口是第一次的切分窗口
    2, 1, //将这个窗口切分成两行一列
    WS_CHILD | WS_VISIBLE, //窗口风格
    m_wndSplitter1.IdFromRowCol(0, 1)
    //指出新切分的窗口是上一次分隔的第一行第二个窗口
    );

    //使用CreateView为第二次切分的第1个窗格产生视图
    m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CTextView),//使用文本视图类
    CSize(150, 120), pContext);

    //使用CreateView为第二次切分的第2个窗格产生视图
    m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CMutView),//使用CMutView视图类
    CSize(250, 250), pContext);

    return 1; //不再调用基类的OnCreateClient函数
    // return CMDIChildWnd::OnCreateClient(lpcs, pContext);
    }

    可见产生第一次切分的方法是,先使用CreateStatic函数产生第一次切分,然后再使用CreateStatic函数对第一次切分所产生的窗口再次切分。

    注意:第二次调用CreateStatic函数切分时,函数的参数有些变化:一是父窗口是第一次的切分窗口,二是ID必须是上次切分窗格的ID。

    (4)在ThreeFrame.cpp文件的开始部分包含下列头文件:

    #include "MutDoc.h"
    #include "MutView.h"
    #include "TextView.h"
    #include "ColorForm.h"

  • 相关阅读:
    TensorFlow学习笔记之四——源码分析之基本操作
    TensorFlow学习笔记之三——适合入门的一些资源
    AW286 选课(背包类树形DP)
    AW303 运输小猫
    AW302 任务安排3
    AW301 任务安排2 (斜率优化DP)
    AW300 任务安排1
    AW311 月之谜
    AW310 启示录
    AW292 炮兵阵地
  • 原文地址:https://www.cnblogs.com/lemon0823/p/2932174.html
Copyright © 2020-2023  润新知