MFC多文档分割窗口
一、MFC多文档结构
MFC多文档结构是一种面向对象的设计模式,用于创建支持多个文档窗口的应用程序。它主要由以下几个类组成:
1. CWinApp:应用程序对象,管理整个应用程序的生命周期。
2. CDocTemplate:文档模板对象,负责创建新的文档和视图对象,并将它们关联起来。
3. CDocument:文档对象,代表应用程序中的一个文档,负责打开、保存和关闭文件等操作。
4. CView:视图对象,代表一个文档窗口中显示的内容,负责处理用户界面和用户交互。
5. CMDIChildWnd:MDI子窗口对象,代表多文档界面中的一个子窗口(通常是一个文档窗口),由用户控制打开、关闭、移动和调整大小等操作。
6. CMDIFrameWnd:MDI主窗口对象,代表多文档界面中的主窗口,包含菜单栏、工具栏、状态栏等用户界面元素。
以上类通过继承和组合相互关联,并协同完成整个MFC多文档应用程序的运行。
二、多文档结构窗口的分割
静态拆分窗口
静态拆分窗口是用 CSplitterWnd::CreateStatic 创建的,但是MVC不会自动创建静态拆分窗口中显示的视图,所以需要亲自在 CreateStatic 返回之后创建视图。 CSplitterWnd提供了名为 CreateView 的函数。
静态拆分窗口的流程
-
给框架窗口类中添加一个 CSplitterWnd 数据成员
(提示:在多文档窗口中只能对MainFrm的ChildFrm进行拆分,如果对MainFrm拆分,会发生中断,原因不详)在ChildFrm.h 文件中定义分割窗口的成员变量
-
Override框架窗口的 OnCreateClient 函数
打开类视图
右击ChildFrm,点击属性,点击重写按钮
找到OnCreateClient 函数并添加,会自动添加在childFrm.cpp里
删除自动创建的OnCreateClient内的所有代码,返回值改为 TRUE;
-
调用 CSplitterWnd::CreateStatic 来创建静态拆分窗口
//先把窗口分割为1行2列的形式,即分割为两列 m_wndSplitter.CreateStatic(this,1, 2 , WS_CHILD | WS_VISIBLE| WS_BORDER);
(拆分过的窗口内是没有view视图的)
-
使用 CSplitterWnd::CreateView 在每个静态拆分窗口中创建视图
//两个窗口填充同样的内容 if(!m_splitter.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(1000, 0), pContext)) return FALSE; if (!m_splitter.CreateView(0, 1, RUNTIME_CLASS(CMyView), CSize(0, 0), pContext)) return FALSE;
第一个参数为行数,第二个参数是列数,第三个参数填写RUNTIME_CLASS,第四个参数为CSize(窗口大小)
RUNTIME_CLASS的定义如下:
#define RUNTIME_CLASS(class_name) ( class_name::GetThisClass() )
注意:RUNTIME_CLASS内的参数必须是一个CView或者他的子类
上述代码中MyView是我自定义的一个类,继承于CView
在解决资源管理器中,右键点击 “ 头文件 ” ,然后点击类向导
点击添加类
基类选择CView
点击完成,然后点击应用、确定。此时一个CView类的派生类已经创建完成
在分割后的窗口上填入相应的视图,此时分割窗口以及完成
编译运行
以上就是一个静态拆分窗口的例程
三、在视图类里添加一个Dialog
经过上述流程,此时用CMyView作为分割窗口的视图窗口,但是CMyView内并没有Dialog,此时我们需要新建一个Dialog的类,把他放到MyView中
右键头文件,点击类向导
添加一个类,基类为CDialogEx
在资源管理器中找到该例程的rc文件并打开
选择刚刚创建的dialog的IDD
此时右侧会弹出一个对话框,可以在工具箱内添加相应的控件,之间拖进来即可
右击dialog,将此dialog的样式改为child,因为此时我们的dialog是需要内嵌在MyView中的
将Visible设置为可见的(TRUE)
一个对话框类就此已经添加完成了,然后我们需要将这个对话框放到刚才创建的MyView里
在MyView.h中声明这个对话框类的指针
按照此前重写ChildFrm的OnCreateClient函数的方法,重写MyView的Create函数,然后在Create中初始化 m_dialog
BOOL CMyView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
// TODO: 在此添加专用代码和/或调用基类
if(!CView::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext))
{
return FALSE;
}
//实例化dialog对象
m_dialog = new MyDialog(this);
//创建dialog
m_dialog->Create(IDD_MYDIALOG,this);
//m_dialog->DoModal();
}
此时分割窗口内填充的是MyView视图,MyView内有个MyDialog
编译运行
四、在MyDialog中添加一个CPropertySheet
CPropertySheet类对象表示属性表,或者说是标签对话框。一个属性表由一个CPropertySheet对象和一个或多个CPropertyPage对象构成。一个属性表由框架来显示,就象是一个具有一系列标签索引的窗口。用户通过这些标签索引来选择当前的页,和一块用于当前所选页的区域。
添加一个CPropertySheet类的子类,方便实现自己的内容
右键头文件,点击类向导,点击添加一个类,基类为CPropertySheet
然后在新建两个CPropertyPage类(可以是N个)
打开CMyPropertySheet.h文件,在类内添加两个属性页成员变量
打开CMyPropertySheet.cpp文件,在两个构造函数中,利用AddPage函数将属性页添加到属性表中
此时属性表类以及创建完成
接下来需要将属性表添加到MyDialog中
在MyDialog内,将CMyPropertySheet的指针添加为成员变量
然后打开类视图,重写CMyDialog::OnInitDialog()函数
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
// TODO: 在此添加额外的初始化
sheet = new CMyPropertySheet(_T("My Property Sheet"), this);
sheet->Create(this, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0);
//获取客户端窗口大小
CRect rect;
GetDesktopWindow()->GetWindowRect(&rect);
//将dialog移动到窗口内
MoveWindow(rect);
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
此时以及将CMyPropertySheet添加进入MyDialog了,编译运行
可以看到,除了之前我们添加过的控件以外,CMyPropertySheet也显示到MyDialog内了