环境:VS2017、Win10
语言:C++
说明:用VS2015可以很方便的进行单文档的视图分割,将界面分成多个右对话框组成的界面。但在VS2017中,无法用类向导创建一个继承自CFormView类与对话框关联,所以分割视图不是很方便,我在看过多篇文章后总结出一种用VS2017分割视图的方法,以此记录。
结果:如下图,左半边是一个带有TeeChart控件的对话框,右半边又分为两行,第一行是继承自CView类的空白行,和新建的单文档界面一样,第二行是一个带有列表控件的对话框。
第一步:创建单文档MFC项目
用VS2017正常创建一个单文档项目,并运行,结果如下图所示:
第二步:添加对话框资源
在资源视图中创建两个对话框,默认ID分别为IDD_DIALOG1、IDD_DIALOG1,可根据自己的喜好修改。然后修改两个对话框的属性:‘Border属性改为None’、‘Style改为Child’。如下图:
第三步:为两个对话框创建继承自CFormView的类
首先点击VS菜单栏的‘视图->类向导’,打开类向导后,然后点击‘添加类->MFC类’,类名设为‘CDlg1’,可更改,基类选择‘CView’。如下图所示:
按照上述方法再生成一个类名为‘CDlg2’继承自CView的类。
打开CDlg1.h头文件,可看到刚刚生成的类的定义,将‘class CDlg1 : public CView’修改为‘class CDlg1 : public CFormView’,,让它继承自CFormView类。在类中添加如下代码:
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_DIALOG1};
#endif
修改结果如下图:
IDD应等于对话框1的ID,然后打开CDlg1.cpp文件,可看到如下代码
修改为:
按照如上步骤修改生成的第二个类CDlg2。修改完成后运行程序,看有无错误发生,若有,按照提示修改错误。运行结果和刚创建完项目的运行结果一样,因为我们才为两个对话框生成了继承自CFormView的类,还未进行视图分割。
第四步:分割视图
打开MainFrm.cpp文件,添加如下头文件:
#include "CSDNDoc.h"
#include "CSDNView.h"
#include "CDlg1.h"
#include "CDlg2.h"
注意第一个头文件和第二个头文件名称应和自己工程中的名称一致,因为我的工程名为‘CSDN’,所以是CSDN+Doc.h和CSDN+View.h,并且这两个头文件顺序不能互换,CSDN+Doc.h必须在CSDN+View.h的前面,否则编译时会报错。报错形式如下图:
然后打开类向导,类名选择CMainFrame,在‘虚函数’中搜索‘create’,选择OnCreateClient,点击‘添加函数’,再点击‘编辑代码’,就可以看到已成功向MainFrm.cpp添加虚函数,过程如下图所示:
接下来就要在这个虚函数中添加分割视图的代码
1.在CMainFrame类中添加两个CSplitterWnd类型的变量m_wndSplitter,m_wndSplitter1;
public:
CSplitterWnd m_wndSplitter, m_wndSplitter1;
2.先将视图分成一行两列
if (!m_wndSplitter.CreateStatic(this, 1, 2))
return FALSE;
3.再将左边的视图(即0行0列)与第一个对话框关联,并设定其宽度为整个视图的一般,高度和整个视图一样高。RUNTIME_CLASS()的参数为与第一个对话框关联的类CDlg1
CRect rc;
GetClientRect(&rc);//获取整个视图大小
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CDlg1), CSize(rc.Width() / 2, rc.Height()), pContext))
return FALSE;
4.将右边视图再分成两行一列
if (!m_wndSplitter1.CreateStatic(&m_wndSplitter, 2, 1, WS_CHILD | WS_VISIBLE, m_wndSplitter.IdFromRowCol(0, 1)))
return FALSE;
5.将第一行与原视图关联,RUNTIME_CLASS()中的参数为原视图类CCSDNView;将第二行与第二个对话框关联,RUNTIME_CLASS()中的参数为第二个对话框关联的类CDlg2
if (!m_wndSplitter1.CreateView(0, 0, RUNTIME_CLASS(CCSDNView), CSize(rc.Width() / 2, rc.Height() / 4), pContext))
return FALSE;
if (!m_wndSplitter1.CreateView(1, 0, RUNTIME_CLASS(CDlg2), CSize(rc.Width() / 2, rc.Height() - rc.Height() / 4), pContext))
return FALSE;
6.整合全部代码如下:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
CRect rc;
// 获取框架窗口客户区的CRect对象
GetClientRect(&rc);
// 创建静态分割窗口,一行二列
if (!m_wndSplitter.CreateStatic(this, 1, 2))
return FALSE;
// 将第0行0列与对话框一关联
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CDlg1), CSize(rc.Width() / 2, rc.Height()), pContext))
return FALSE;
//在第0行1列上创建一个两行一列的分割窗口
if (!m_wndSplitter1.CreateStatic(&m_wndSplitter, 2, 1, WS_CHILD | WS_VISIBLE, m_wndSplitter.IdFromRowCol(0, 1)))
return FALSE;
//分别关联视图
if (!m_wndSplitter1.CreateView(0, 0, RUNTIME_CLASS(CCSDNView), CSize(rc.Width() / 2, rc.Height() / 4), pContext))
return FALSE;
if (!m_wndSplitter1.CreateView(1, 0, RUNTIME_CLASS(CDlg2), CSize(rc.Width() / 2, rc.Height() - rc.Height() / 4), pContext))
return FALSE;
return TRUE;
}
第五步:在对话框中添加控件并为控件关联变量
1.在资源视图中打开对话框一和二,分别拖入TeeChart控件和列表控件,在本文中只讲列表控件,如何在VS2017单文档MFC程序中加入TeeChart控件可自行在网上找其他的教程,这个在以后的博客中我也会介绍。添加列表控件后,在属性中将‘View’属性设置为‘Report’。
2.此时点击列表视图后右键,选择‘添加变量’,填写变量名称后点击‘完成‘会发现出现错误提示“为将对象引用设置到对象的实例”
看来此项目中不能直接添加变量,接下来打开类向导,向CDlg2类中添加虚函数DoDataExchange,步骤如下图所示:
然后在在资源视图中打开对话框2,点击列表控件,右键添加变量,变量名称设为m_List1,然后点击完成,此时发现在刚刚添加的DoDataExchange虚函数中多了行代码“DDX_Control(pDX, IDC_LIST1, m_List1);”转到CDlg2类的定义中也发现有“CListCtrl m_List1;”。但是会发现报错“未定义标识符IDC_LIST1”,很明显这个标识符是列表控件的ID,它被定义在Resource.h,打开这个头文件查看有无此定义,打开后发现是有的,可以无视此错误提示,关闭Resource.h。编译运行程序,发现并未出现错误提示,此时就已成功为列表控件添加了变量。
简而言之,在添加变量前要先添加DoDataExChange虚函数,再添加变量。
7.为列表控件中添加内容
首先为对话框2添加初始化的虚函数,名为OnInitialUpdate,步骤如下图:
再向此函数中添加如下代码:
m_List1.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);//设置列表控件格式(有栅格线,整行选中)
m_List1.SetBkColor(RGB(255, 255, 255));//设置列表控件背景为白色
m_List1.InsertColumn(0, _T("姓名"), LVCFMT_CENTER, 160);//添加列,并设置列的宽度为160
m_List1.InsertColumn(1, _T("性别"), LVCFMT_CENTER, 160);
m_List1.InsertColumn(2, _T("年龄"), LVCFMT_CENTER, 160);
m_List1.InsertItem(0, _T("张三")); m_List1.SetItemText(0, 1, _T("男")); m_List1.SetItemText(0, 2, _T("21"));//添加数据
然后运行,最终结果如下:
本文工程百度云链接:https://pan.baidu.com/s/1dXvvg2iEykT0ZPc1tLp4Dg 提取码:mr9h
本文工程CSDN下载链:https://download.csdn.net/download/weixin_41303441/11743253
本文开头显示结果的工程百度云链接(含TeeChart控件及控件大小随窗口大小而变):https://pan.baidu.com/s/1jJOvKNsnHvrfgZO77GEiCg 提取码:kg5e
本文开头显示结果的工程CSDN下载链(含TeeChart控件及控件大小随窗口大小而变):https://download.csdn.net/download/weixin_41303441/11743278