所用环境:Windows10 64位操作系统、VC++6.0编译器、MFC开发架构
实现功能:在MFC程序的单文档模式下,将窗口进行分割(拆分),结果如下
可以看到,在单文档下,窗口被分为了左右两个部分,左侧包含各种可视化控件,右侧就是正常的绘图区。
接下来我们开始一步步的实现这种效果。
以下内容分为如下几个部分:
1.创建工程
2.可视化编辑左侧窗体
3.在MainFrame.cpp中将初始窗口分割(拆分)为两个部分
4.使用Doc文档作为桥梁,使数据可以在左侧窗体和右侧窗口之间传递
1.创建工程
首先我们新建项目,选择工程,MFC APPWizard[exe]子项目,工程名设置为Test02,C位置就是工程文件的保存位置。
再点击确定之后,选择单个文档类型,然后其他配置使用缺省设置,直接单击完成即可。
单击确定继续操作
这个时候我们就创建好了项目,接下来我们开始先创建一个我们需要的左侧窗口,因为右侧的绘图窗口工程中是默认存在的。
2.可视化编辑左侧窗体
在ResourceView选择卡中,我们可以看到Dialog中包含一个AboutBox,这个是帮助按钮的弹窗,我们在Dialog文件夹上右击,选择“Insert Dialog”选项
系统会自动创建一个ID为IDD_DIALOG1的窗口,我们右击这个窗口,选择最低侧的属性选项
在这个窗口的General选择卡中,我们可以配置这个窗体的ID和标题,这里我们直接使用默认的即可
然后我们转到Styles选择卡中进行一些配置,将Style改为Child,子窗口。Border设置为None,无。
之后我们就可以看到我们的窗体变成了这样
我们直接将默认的两个按钮删除。鼠标左键单击选中按钮控件,使用键盘上的DEL键删除即可。
(注:DEL为一组六个键中INS键下面的键,也是数字键盘中’.'的另一种功能键)
接下来我们在红点出右击鼠标,会弹出如下的窗口,我们使用鼠标左键单击Controls,就可以呼出一个基本的可视化窗口控件窗口,如下图
然后我们添加两个按钮到我们的窗体中。添加过程为:鼠标左键选择红框位置的图标,将鼠标移动到窗体中,你想要添加按钮的位置,再次左键单击即可完成添加。
随后我们选择其中一个按钮控件,右击选择属性。在General选择卡里面,我们可以给这个按钮设置它的ID和标题。设置完成之后,直接单击窗口右上角的X,即可关闭属性配置窗口,在这里面更改的参数会自动同步保存。
加下来我们双击第一个名为“确定”的按钮,就可以给这个按钮添加一个对应的单击处理事件。可以看到弹出一个窗口,这个窗口问我们,要使用这个功能,就必须为这个对话框(窗口)绑定一个类,我们是想“Create a new class”创建一个新的类,还是选择一个已有的类。因为我们并没有创建什么跟类有关的东西,所以我们选择创建一个新的类,单击ok。
在我们单击OK按钮之后,就会弹出这么一个窗口,让我们设置类的一些属性,比如类名,这个类的父类,以及这个类所对应的Dialog ID等。我们按照图片给这个类设置参数。
在创建完窗口所绑定的类之后,我们在这个窗口里面找到我们原来设置的按钮的ID,然后为其添加一个ID为BN_CLICKED的函数,也就是鼠标单击此按钮的处理事件函数。
在单击Add Function按钮之后,会弹出这个窗口,询问你所要添加的事件处理函数的名字是什么,这里就直接使用默认的名字即可。
我们可以看到在下面的Member functions里面已经多了一个我们刚刚添加的函数,这个时候我们单击Edit Code按钮,就可以进入到代码文件中,对这个按钮的事件处理函数进行编码。
可以看到现在我们所处的位置就变换到了LeftWindow.cpp里面,所浏览的函数也就是我们原来添加的OnTest01。
现在我们先不往里面加东西。
3.在MainFrame中分割(拆分)窗口
接下来我们进入FileView选择卡,在Header Files目录下的MainFrame.h中,添加这么一行代码: CSplitterWnd m_wndSplitter; 就是说我们定义了一个变量,一个CSplitterWnd 类型的变量,名字叫m_wndSplitter。做这一步操作不用添加头文件,也不用做其他事情,只需要将代码放到这个位置即可。将代码放到这个位置之后,我们Build一个项目,可以发现左侧的目录树多出了一个目录“External Dependencies”。
然后我们进入到MainFrame.cpp中,使用Ctrl+W快捷键(或者鼠标右键选择,建立类向导Class Wizard),为这个类添加一个名为OnCreateClient的函数,这个函数会在创建窗口的时候被调用。
创建好函数之后,我们直接使用如下内容替换掉函数里面的内容
代码很简单,第一行是将此窗口分为一行两列的区域。
第二行是在0,0位置的区域,放上我们原来创建的LeftWindow窗口,大小是190x600。
第三行是在0,1位置的区域,放上我们系统默认生成的CTest02View绘图窗口,大小是520x600。
注:这里要注意一个地方,就是CTest02View这个类,你从左侧看,它的文件名字是Test02VIew.cpp和Test02View.h,但是它的类名,当你双击到Test02View.h里面之后会发现,它的类名是CTest02View
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
m_wndSplitter.CreateStatic(this,1,2);
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(LeftWindow),CSize(190,600),pContext);
m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CTest02View),CSize(520,600),pContext);
return TRUE;
}
这个时候我们直接Build,编译器是会直接报错的,提示我们没有这两个类。这个时候我们只需要在文件上面使用#include "xxxx.h"将它们包含进来即可
这个时候我们编译的话,还是会报错。对于这个错,我们只需要在这个文件(Test02View.h)的上面加上这个即可 #include “Test02Doc.h”,将Test02Doc这个文档类包含进来。
这个时候我们编译运行项目之后,就可以看到我们的窗口被分为了两个部分。如下
4.左右窗口间数据的传输
到这里,基本上就已经完成了,接下来就是在左右窗口之间架起一个桥梁,让它们之间的数据可以互通共享。 这里我所使用的方式是借助文档类来做这个桥梁。 我们首先在Test02Doc.h中,添加两个CPoint对象。
然后我们就可以在左右窗口中使用它们。
使用的时候加上如下代码即可
修改时
CTest02Doc *pDoc =(CTest02Doc*)GetDocument();// 获取文档
CPoint start,end;
start.x = 0, start.y = 0;
end.x = 100, end.y = 100;
// 更改数据
pDoc->p1 = start;
pDoc->p2 = end;
pDoc->UpdateAllViews(NULL);// 更新数据
使用时
CSubWindowTestDoc* pDoc = GetDocument();// 获取文档
ASSERT_VALID(pDoc);// 同步数据
// TODO: add draw code for native data here
// 使用数据
pDC->MoveTo(pDoc->p1);
pDC->LineTo(pDoc->p2);
我们在LeftWindow.cpp中的按钮事件处理函数中添加修改时的代码,在Test02View.cpp中的OnDraw函数下添加使用时的代码。
注意:因为Test02View.cpp中的OnDraw函数中,自动生成了前两行代码,所以在添加的时候只需要添加下面两行代码即可。
项目运行效果展示
编译运行
在单击确定按钮之后