开发环境:Visual Studio 2012
1 单文档窗口分割
单文档窗口分割可以借助CSplitterWnd类来实现,具体操作见参考资料[2]。由于静态窗口分割使用的更多,这里只描述在创建静态窗口过程中遇到的问题。
1.1 问题1
由于要使用到*View类,而*View类又用到*Doc类,因此需要在MainFrm.cpp中添加其头文件,例如
#include "WindowSplitDoc.h" #include "WindowSplitView.h"需要注意的是,*Doc.h必须在*View.h前面。
1.2 问题2
如果只是调用CSplitterWnd类的CreateStatic函数创建了静态分割窗口,而没有调用其CreateView函数来创建视图,则在运行时报错:
if (!m_wndSplitter.CreateStatic(this, 2, 1)) return FALSE;
1.3 问题3
CMainFrame::OnCreateClient函数默认的返回值为
return CFrameWndEx::OnCreateClient(lpcs, pContext);必须将其改为
return TRUE;否则,分割不成功!
2 多文档窗口分割
根据参考资料[9]的125页的说明,这里将介绍一种非常简单的实现方法,这种方法同样适用于单文档窗口分割。
在MFC提供的程序设计向导MFC AppWizard的如下界面中,选择“用户界面功能”
在如下界面中,勾选“拆分窗口”,然后点击“完成”即可。
运行上述的程序,你可能没有看到拆分窗口,那是因为分界线在最顶端和最左端!要把鼠标移到最顶端/最左端分界线的位置,按住左键往下/右移动就可以看到拆分效果了。
注意: 这种方法的拆分结果默认情况下是动态的,而且是拆分为4个窗口。可以按参考资料[2]修改为静态拆分,或者修改拆分窗口的布局。
3 对话框窗口分割
基于对话框的MFC程序窗口的分割,可以见参考资料[1][7]。鉴于参考资料有些表述不清的地方,这些将详细记录对话框窗口分割过程。
3.1 创建基于对话框的程序
创建一个MFC对话框程序MySplitterDlg。
3.2 插入Dialog
在“资源视图”中选择右键单击Dialog,选择“插入Dialog”:
用上述方法插入两个对话框:
根据参考资料[1]的说明,将上述新添加的两个对话框的属性Border和Style分别设置为None和Child。
为了便于区别两个不同的对话框,将各种的默认按钮控件都以及其其它控件都删除,然后分别添加静态文本控件,文件内容分别为“IDD_DIALOG1”和“IDD_DIALOG2”。
3.3 创建对话框类
为上述的两个对话框分别创类CMyFormView0 和CMyFormView1,基类别选CDialog,一定要选择CFormView:
创建完成后,类视图如下:
3.4 增加WM_CREATE消息响应函数OnCreate
通过“类向导”为“CMySpliterDlgDlg类(不要选择其它类)添加WM_CREATE的消息响应函数:
3.5 编辑OnCreate
添加了消息函数OnCreate之后,编辑其内容如下:
int CMySplitterDlgDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialogEx::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 // Because the CFRameWnd needs a window class, we will create a new one. I just copied the sample from MSDN Help. // When using it in your project, you may keep CS_VREDRAW and CS_HREDRAW and then throw the other three parameters. //需要注册窗口类 CString strMyClass = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, ::LoadCursor(NULL, IDC_ARROW), (HBRUSH) ::GetStockObject(WHITE_BRUSH), ::LoadIcon(NULL, IDI_APPLICATION)); // Create the frame window with "this" as the parent m_pMyFrame = new CFrameWnd; m_pMyFrame->Create(strMyClass,_T(""), WS_CHILD, CRect(0,0,300,300), this); m_pMyFrame->ShowWindow(SW_SHOW); // and finally, create the splitter with the frame as the parent m_cSplitter.CreateStatic(m_pMyFrame,1, 2); //在Frame里切分视图窗口为1×2,就是一行两列 m_cSplitter.CreateView(0,0, RUNTIME_CLASS(CMyFormView0), CSize(100,100), NULL);//第一行一列 m_cSplitter.CreateView(0,1, RUNTIME_CLASS(CMyFormView1), CSize(100,100), NULL);//第一行二列 return 0; }
注意:m_pMyFrame-Create()中的字符串(双引号中的空字符串)需要使用_T()进行长字符转换,见上述代码。
3.5.1 添加CFrameWnd变量
由于上述程序中用到变量m_pMyFrame,因此需要在类CMySplitterDlgDlg中添加
public: CFrameWnd *m_pMyFrame;
为了防止内存泄露,在onDestroy()中添加
if (m_pMyFrame) delete m_pMyFrame;
3.5.2 添加Dialog头文件
此外,由于上述程序还用到了3.3小结所创建的类CMyFormView0和CMyFormView1,因此需要在MySplitterDlgDlg.cpp中添加其头文件
#include "MyFormView0.h" #include "MyFormView1.h"3.5.3 添加CSplitterWnd变量
由于分割窗口时使用到了CSplitterWnd类(见上述OnCreate函数),因此需要在类CMySplitterDlgDlg中添加
CSplitterWnd m_cSplitter;
3.6 编辑OnSize
添加了消息函数OnCreate之后,编辑其内容如下:
void CMySplitterDlgDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 CRect cRect; GetWindowRect(&cRect); ScreenToClient(&cRect); m_pMyFrame->MoveWindow(&cRect); m_pMyFrame->ShowWindow(SW_SHOW); }
说明:参考资料[7]中将上述的内容添加在OnInitDialog()函数中。那样虽然也可以显示分割效果,但是放大窗口时分割的窗口并不同步放大。因此,还是将其放在OnSize()中比较适合。
参考资料
[1]基于MFC的窗口拆分
[2]VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)
[3]MFC分割窗口的实现
[4]不用splitter控件 简单实现对mfc对话框的分割的方法
[5]Creating a Splitter Window in a Dialog Box in Three Easy Steps
[6]高分悬赏基于对话框的mfc分割两个窗口
[7]VC实现对话框窗口任意分割
[8]MFC中CSplitter的应用以及在View中添加按钮
[9]《MFC Windows应用程序设计》(第3版). 任哲 等编著. 清华大学出版社
[10]MFC中单文档窗口的拆分
[11]MFC拆分窗口及它们之间的数据交换