操作系统:Windows 7
软件环境:Visual Studio 2008 SP1
本次目的:在单文档程序中动态切换多个窗体
此文章转自网上,本人在最新的2008 SP1试验通过,现将步骤(转帖)和过程图片(本人自己截图)记录如下。
摘要:本文通过一个程序实例描述了在VC++6.0下如何在单文档程序中通过菜单动态控制多个窗体的切换。
一、 引言
我们在编制程序中根据需求的不同会在程序风格上选择多文档、单文档或是对话框模式,对于单文档模式可能是我们使用比较多的,但有时我们想采用单文档的形式显示多个不同的窗体,如作为数据库前台应用程序就会遇到此类问题,数据库由大量的表单组成,而同常一个窗体内只用来显示一个表单,所以要显示其他的表单时就要用到切换窗体的技术了,下面就通过一个程序说明该技术的实现方法。
二、 实现技术
新建一个基于CFormView的单文档应用程序,再添加一个窗体和与之对应的基于CFormView的新视类,然后通过在主框架类里添加控制代码和菜单控制实现这两个窗体的动态切换,下面就是具体的实现过程:
(一) 用"MFC AppWizard(exe)"建立一个新项目"SwitchForm",并在第二步的创建类型上选择为"Single documnet"单文档模式,若是vc++2008 sp1版本的还需要在项目类型里面选择"MFC标准",第三、四、五、六步均取确省状态,最后一步选择"CFormView"作为视类的基类。点按"完成"按钮,生成了初始工程"SwitchForm"。
(二) 点选菜单"Insert"、"Resource…",在弹出的"Insert Resource"对话框中"Dialog"树里的"IDD_FORMVIEW",点击"New"按钮,生成了一个新的窗体,将其ID号改为"IDD_NEXTFORM"。在原有的窗体上加一个静态框"这是第一个窗体";在新建的窗体上也添加一个静态框"这是第二个窗体"。
(三) 在菜单资源的"IDR_MAINFRAME"上添加一级菜单"窗体切换",及其二级菜单"第一个窗体"、"第二个窗体",其标识号分别为"ID_FIRSTFORM"和"ID_SECONDFORM"。修该"第一个窗体"的属性为"Checked",表明程序初始时显示的是第一个窗体。
(四) 在"ClassView"属性页里的"SwitchForm classes"上右键,在弹出菜单上选择"New Class…",弹出"New Class"对话框,选择"Dialog ID:"为我们刚添加的新窗体"IDD_NEXTFORM",选择"Base class:"为"CFormView",类名取为"CNextFormView",这样就把第二个窗体对应的视图类添加到了工程。
(五) 在框架类里添加函数
// MainFrm.h : CMainFrame 类的接口
class CMainFrame : public CFrameWndEx
{·····
public:
void SwitchToForm(int nForm);
·····}
// MainFrm.cpp : CMainFrame 类的实现
void CMainFrame :: SwitchToForm(int nForm)
{
//获取原来的活动窗体的视图句柄
CView*pOldActiveView=GetActiveView();
//获取由"nForm"标识的窗体所对应的视图句柄
CView*pNewActiveView=(CView*)GetDlgItem(nForm);
//若视图句柄为空,则创建一新的。
if(pNewActiveView==NULL)
{
if(nForm==IDD_SWITCHFORM_FORM)
pNewActiveView=(CView*)new CSwitchFormView ;
if(nForm==IDD_NEXTFORM)
pNewActiveView=(CView*)new CNextFormView ;
CCreateContext context ;
context.m_pCurrentDoc=pOldActiveView->GetDocument();
pNewActiveView->Create(NULL,NULL,0L,CFrameWnd :: rectDefault,this,nForm,&context);
pNewActiveView->OnInitialUpdate();
}
//选择pNewActiveView为活动窗体
SetActiveView(pNewActiveView);
//显示活动窗体,隐藏非活动窗体
pNewActiveView->ShowWindow(SW_SHOW);
pOldActiveView->ShowWindow(SW_HIDE);
int ID ;
if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CSwitchFormView))
ID=IDD_SWITCHFORM_FORM ;
if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CNextFormView))
ID=IDD_NEXTFORM ;
//设置窗体的ID号
pOldActiveView->SetDlgCtrlID(ID);
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
RecalcLayout();
}
(六)添加两个菜单相对应的命令响应函数和更新函数如下:
void CMainFrame::OnFirstform()
{
//通过IsKindOf函数确定当前活动窗口是否是第一个窗口,如是,则无须切换,否则将通过SwitchToForm函数将当前活动窗口切换到"IDD_SWITCHFORM_FORM"标识的第二个窗体。
if (GetActiveView()->IsKindOf(RUNTIME_CLASS(CSwitchFormView)))
return;
SwitchToForm(IDD_SWITCHFORM_FORM);
}
void CMainFrame::OnUpdateFirstform(CCmdUI *pCmdUI)
{
//通过IsKindOf函数判断当前活动窗口是否是第一个窗体,如是则将其选中。
pCmdUI->SetCheck(GetActiveView()->IsKindOf(RUNTIME_CLASS(CSwitchFormView)));
}
void CMainFrame::OnSecondform()
{
if (GetActiveView()->IsKindOf(RUNTIME_CLASS(CNextFormView)))
return;
SwitchToForm(IDD_NEXTFORM);
}
void CMainFrame::OnUpdateSecondform(CCmdUI *pCmdUI)
{
pCmdUI->SetCheck(GetActiveView()->IsKindOf(RUNTIME_CLASS(CNextFormView)));
}
然后再在该文件开始处添加对两个视图类的引用:
#include "SwitchFormDoc.h"
#include "SwitchFormView.h"
#include "NextFormView.h"
在此须注意:应在两个视类的引用之前添加对文档类的引用,否则会引起编译错误。另外,由于视类的构造函数在声明时都确省的声明为保护型的,在框架类中无法引用,所以还要将两个视类的类声明改动如下:
class CNextFormView : public CFormView
{
public: //将protected 改为public.
CNextFormView();
……
};
class CSwitchFormView : public CFormView
{
public: //将protected 改为public.
CSwitchFormView();
……
};
三、 编译运行
编译运行程序,开始时的窗体上有"这是第一个窗体的字样",菜单也只有"第一个窗体"是被选中的,当前的活动窗体是第一个窗体;点击菜单"第二个窗体",视图中的窗体上的字样变成了"这是第二个窗体",同时选中的菜单也由"第一个窗体"变成了"第二个窗体",实现了通过菜单将窗体进行动态切换。
总结:此程序中关键的是SwitchToForm函数,在此函数中,程序搜索所有当前文档的显示窗口来查找与CruntimeClass变量匹配的视图类。如果找到,该窗口被激活。通过与之类似的方法,还可以实现在多文档模式下的单档(文档)多视(视图),通过不同的视图以不同的方式显示来自同一份文档的数据,以更好的满足程序的需要。