MFC视图切换大全总结
单纯视图之间的切换
单文档多视图切换是我在学习MFC中遇到的一个老大难问题,在今天总算是一一破解了。我觉得视图切换分为三个等级,第一是在未切分窗格的情况下切换视图类;第二是在分割窗格的一个窗格内实行视图切换;第三是在分割窗格和未分割之间的切换和视图切换。
在MFC创建SDI的伊始,MFC默认的视图类是CView,如果CView满足你的需求,可以直接单击finish,如果你不想让CView成为你的默认视图类,你可以在下图这个地方修改。
如果你忘记了修改默认的视图类这也没关系,我们可以在代码中改变:
在App类里面有个函数叫InitInstance(),在这里面有一段代码
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(Cprogram8Doc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CView1)); //这里更改你的默认视图类,注意不要忘记包含头文件哦
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
说完了默认视图类的更改,我们现在进入主题。
1、首先创建你需要切换的视图类,AddClass进入或者创建一个控件然后AddClass创建控件关联类,后者适用于Form之类的控件。
2、控制之处,比如菜单项单击、单击鼠标什么的,我是使用菜单项来切换窗口的
void CMainFrame::OnView1()
{
// TODO: Add your command handler code here
SwitchToForm(IDD_FORMVIEW1);
}
void CMainFrame::OnView2()
{
// TODO: Add your command handler code here
SwitchToForm(IDD_FORMVIEW2);
}
3、SwitchToForm这个函数主要用于视图切换
在这个函数中主要做以下几个动作:
1、获得当前视图类指针和需要转换的视图类指针,如果是第一次使用需要New一个,并且与文档类关联;
2、改变活动视图;
3、显示新视图和隐藏旧视图;
4、设置控件ID;
5、调整框架视图。
void CMainFrame::SwitchToForm(int nForm)
{
CView *pOldActiveView=GetActiveView(); //1
CView *pNewActiveView=(CView*)GetDlgItem(nForm);
if(NULL==pNewActiveView)
{
switch(nForm)
{
case IDD_FORMVIEW1:
pNewActiveView=(CView*)new CView1;
break;
case IDD_FORMVIEW2:
pNewActiveView=(CView*)new CView2;
break;
case IDD_FORMVIEW3:
pNewActiveView=(CView*)new CView3;
break;
case IDD_FORMVIEW4:
pNewActiveView=(CView*)new CView4;
break;
default:
break;
}
CCreateContext context;
context.m_pCurrentDoc=pOldActiveView->GetDocument();
pNewActiveView->Create(NULL,NULL,WS_CHILD | WS_BORDER,CFrameWnd::rectDefault,this,nForm,&context);
pNewActiveView->UpdateData();
}
SetActiveView(pNewActiveView); //2
pNewActiveView->ShowWindow(SW_SHOW); //3
pOldActiveView->ShowWindow(SW_HIDE);
if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView1)) //4
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW1);
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView2))
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW2);
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView3))
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW3);
else if(pOldActiveView->GetRuntimeClass()==RUNTIME_CLASS(CView4))
pOldActiveView->SetDlgCtrlID(IDD_FORMVIEW4);
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
RecalcLayout(); //5
}
在看网上其他人的帖子的时候发现在RecalcLayout(); 前面还要加一句delete pOldActiveView;我自己觉得这样有些浪费资源,视图类创建完成了隐藏起来,用的时候重新显示。这样的方法应该比每次使用都要创建好一些。小弟不才,有讨论的朋友可以联系我。
带有分割窗格的视图切换
切换视图第二层就是带有分割窗格的视图切换
分割窗格的视图切换,我觉得难点是不容易在有限区域进行视图切换。
1、首先分割窗格,这里我不多解释,详情看下面链接;
2、再给每个视图一个唯一的ID号;
m_splitter.CreateStatic(this,1,2);
m_splitter.CreateView(0,0,RUNTIME_CLASS(CTree1),CSize(100,100),pContext);
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm1),CSize(100,100),pContext);
CWnd *pWnd=m_splitter.GetPane(0,1);
m_pViews[0]=(CView*)m_splitter.GetPane(0,1);
pWnd->SetDlgCtrlID(IDD_FORM1);
pWnd->ShowWindow(SW_HIDE);
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm2),CSize(100,100),pContext);
pWnd=m_splitter.GetPane(0,1);
m_pViews[1]=(CView*)m_splitter.GetPane(0,1);
pWnd->SetDlgCtrlID(m_splitter.IdFromRowCol(0,1));
pWnd->ShowWindow(SW_SHOW);
RedrawWindow();
return true;
注:我这里CreateView一个新视图,就覆盖掉前一个视图,最终显示的是最后一个视图,前面的视图只是隐藏起来,等到使用的时候显示出来就好了。返回值要覆盖返回到基类的语句return CFrameWndEx::OnCreateClient(lpcs, pContext);将这句话注解,然后return true;
3、在哪里激活切换功能自己设计,我使用的是菜单;
4、响应主要包括下面几个步骤:
1、首先获得窗格中的当前视图;
2、使用IsKindOf判断这个类是否是将要切换到的类;
3、获得框架长宽和窗格长宽;
CView *pView=(CView*)m_splitter.GetPane(0,1); //1
m_bTest=pView->IsKindOf(RUNTIME_CLASS(CForm2)); //2
CRect rcFrame,rcClient; //3
m_splitter.GetClientRect(&rcClient);
GetClientRect(&rcFrame);
上面的全部是准备工作,下面才是真正的切换;
4、删除原有视图
5、创建当前视图
6、调整框架
if(m_bTest)
{
m_splitter.DeleteView(0,1);
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm1),CSize(rcClient.Width(),rcFrame.Height()),NULL);
m_splitter.RecalcLayout();
}
else
{
m_splitter.DeleteView(0,1);
m_splitter.CreateView(0,1,RUNTIME_CLASS(CForm2),CSize(rcClient.Width(),rcFrame.Height()),NULL);
m_splitter.RecalcLayout();
}
仔细一看,貌似这个还要比单纯视图切换还要简单一些,这也没办法,CSplitterWnd提供了这么一个便捷的方法。
带分割视图与未分割视图之间的切换
这个是三部曲中我认为最难的,并不是说程序有多么难,只是想到这个切分方式真的不容易,今天就把这三部曲的最后一曲分享给大家,也为互联网做一点贡献。
首先说一下程序的思想,为分割窗口层专门独立创建一个基于CFrameWnd的类,然后在这里面写分割视图的代码,再与其他未分割的视图类进行切换。
下面我们来看一下实现的过程:
1、创建一个基于CFrameWnd的派生类CSplitterFrame;
2、添加要填充分割窗口的视图类和与分割视图切换的视图类;
3、为这个派生类重载OnCreateClient函数,构造分割视图
m_Splitter.CreateStatic(this,1,2);
m_Splitter.CreateView(0,0,RUNTIME_CLASS(CLeftTree),CSize(300,0),pContext);
m_Splitter.CreateView(0,1,RUNTIME_CLASS(CRightList),CSize(300,0),pContext);
return true;
这里我不解释了,想必大家都很熟悉了,这里我要说一点我自己犯过的错误。我本来想在这里GetClientRect获得窗口大小,但失败了,左思右想不明白,后来才发现,这又不是CMainFrame,所以根本不能获得,要是用API函数。
4、在CMainFrame类里面添加框架和视图类指针变量
CSplitterFrame *m_pSplitterFrame; //分割视图框架指针
CView *m_pView; //单独视图类,基于CView类
CView *m_pForm; //单独视图类,基于CFormView类
int m_nCurrentID; //记录当前视图
5、在CMainFrame类里面重载OnCreateClient函数,创建视图及分割框架
CRect rcClient;
GetClientRect(&rcClient);
m_pView=new CViewShow;
m_pView->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,NULL,pContext);
m_pView->ShowWindow(SW_SHOW);
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
pContext->m_pNewViewClass=(CRuntimeClass*)m_pView; //设置默认视图类
m_pForm=new CFormShow;
m_pForm->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,IDD_FORMSHOW,pContext);
m_pForm->ShowWindow(SW_HIDE);
m_pSplitterFrame=new CSplitterFrame;
m_pSplitterFrame->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW &~WS_BORDER,rcClient,this,NULL,0,pContext);
m_pSplitterFrame->ShowWindow(SW_HIDE);
return true;
6、创建视图切换函数
bool CMainFrame::Switch(int nID)
{
if(nID==m_nCurrentID)
return false;
switch(nID)
{
case IDD_FORMSHOW:
m_pForm->ShowWindow(SW_SHOW);
m_pForm->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pView->ShowWindow(SW_HIDE);
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST+2);
m_pSplitterFrame->ShowWindow(SW_HIDE);
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST+1);
m_nCurrentID=IDD_FORMSHOW;
break;
case AFX_IDW_PANE_FIRST+1:
m_pSplitterFrame->ShowWindow(SW_SHOW);
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pForm->ShowWindow(SW_HIDE);
m_pForm->SetDlgCtrlID(IDD_FORMSHOW);
m_pView->ShowWindow(SW_HIDE);
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST+2);
m_nCurrentID=AFX_IDW_PANE_FIRST+1;
break;
case AFX_IDW_PANE_FIRST+2:
m_pView->ShowWindow(SW_SHOW);
m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pForm->ShowWindow(SW_HIDE);
m_pForm->SetDlgCtrlID(IDD_FORMSHOW);
m_pSplitterFrame->ShowWindow(SW_HIDE);
m_pSplitterFrame->SetDlgCtrlID(AFX_IDW_PANE_FIRST+1);
m_nCurrentID=AFX_IDW_PANE_FIRST+2;
break;
default:
break;
}
RecalcLayout();
return true;
}
7、创建调用方法
void CMainFrame::OnForm()
{
// TODO: Add your command handler code here
Switch(IDD_FORMSHOW);
}
void CMainFrame::OnView()
{
// TODO: Add your command handler code here
Switch(AFX_IDW_PANE_FIRST+2);
}
void CMainFrame::OnSplitter()
{
// TODO: Add your command handler code here
Switch(AFX_IDW_PANE_FIRST+1);
}
MFC视图切换大全总结的更多相关文章
- MFC中窗口静态分割&视图切换
目录 窗口静态分割 单个分割器 声明 准备视图 静态分割窗口&添加视图 使视图大小随窗口大小改变 多个分割器 声明 静态分割窗口&添加视图 使视图大小随窗口大小改变 视图切换 视图之间 ...
- iOS开发系列--视图切换
概述 在iOS开发中视图的切换是很频繁的,独立的视图应用在实际开发过程中并不常见,除非你的应用足够简单.在iOS开发中常用的视图切换有三种,今天我们将一一介绍: UITabBarController ...
- pushViewController addSubview presentModalViewController视图切换
1.pushViewController和popViewController来进行视图切换,首先要确保根视图是NavigationController,不然是不可以用的, pushViewContro ...
- IOS 视图切换动画
我在网上找到的这个小方法,被我举一反三使用的屡试不爽.比如用在,当视图需要执行某一方法跳转到新的一个UIView上,从底层渐变浮到最上层.就是一个不错的视觉效果或者当需要类似keyboard的效果从底 ...
- UI3_视图切换
// // ViewController.m // UI3_视图切换 // // Created by zhangxueming on 15/7/3. // Copyright (c) 2015年 z ...
- UI2_视图切换ViewController
// // SubViewController.h // UI2_视图切换 // // Created by zhangxueming on 15/7/3. // Copyright (c) 2015 ...
- UI1_ViewController视图切换及Appdelegate
// // ThirdViewController.h // UI1_ViewController视图切换及Appdelegate // // Created by zhangxueming on 1 ...
- UI2_视图切换
// // ViewController.m // UI2_视图切换 // // Created by zhangxueming on 15/7/1. // Copyright (c) 2015年 z ...
- Tabbar视图切换,返回上一视图,添加item
前面有一篇博文iOS学习之Tab Bar的使用和视图切换 这是在AppDelegate里使用Tabbar,这样的程序打开就是TabbarView了,有时候我们需要给程序做一些帮助页面,或者登录页面,之 ...
随机推荐
- 学习PHP C扩展之面向对象开发方式 (转)
PHP OOP面向对象之C语言开发方式 学习PHP C扩展有一段时间了,PHP手册里大部分讲的PHP的函数开发方式,网上找OOP资料比较少,想起上个月测试redis 的时候,下载PHP扩展redis源 ...
- 随机变量的方差variance & 随机向量的协方差矩阵covariance matrix
1.样本矩阵 如果是一个随机变量,那么它的样本值可以用一个向量表示.相对的,如果针对一个随机向量,那么就需要利用矩阵表示,因为向量中的每一个变量的采样值,都可以利用一个向量表示. 然后,一个矩阵可以利 ...
- 多线程程序设计学习(5)balking模式和timed模式
Balking[返回模式]timed[超时模式]一:balking pattern的参与者--->GuardedObject(被警戒的对象) --->该模式的角色:模拟修改警戒对象的线程, ...
- JS实现连接方式的菜单
<html> <head><meta http-equiv="Content-Language" content="zh-cn"& ...
- wifi详解(一)
1 WLAN技术 WLAN是英文WirelessLAN的缩写,就是无线局域网的意思.无线以太网技术是一种基于无线传输的局域网技术,与有线网络技术相比,具有灵活.建网迅速.个人化等特点.将 ...
- Linux系统性能监控
系统的性能指标主要包括CPU.内存.磁盘I/O.网络几个方面. 1. CPU性能 (1)利用vmstat命令监控系统CPU 该命令可以显示关于系统各种资源之间相关性能的简要信息,这里我们主要用它来看C ...
- 完美完全卸载Oracle 11g数据库
Oracle 11g可在开始菜单中卸载,然后同时需要删除注册表中相关内容. 操作系统:windows10专业版. 卸载步骤: 1.停用oracle服务:进入计算机管理,在服务中,找到oracle开头的 ...
- Oracle 存储过程的创建,及触发器调用存储过程
一.创建存储过程 1.存储过程写法 create or replace procedure HVM_BYQ_TJ --变压器统计信息--->入库 (id in number) as begin ...
- MyBatis的association示例——MyBatis学习笔记之三
前两篇博文介绍的都是单表映射,而实际上很多时候我们需要用到较复杂的映射.今天学会的association的用法,就是一例,现写出来和大家分享(为简洁起见,ant工程中各文件.目录的布局,以及其它与前面 ...
- Android UI开发详解之Fragment
Fragment是Android自从3.0之后新加入的一个组件,我相信很多人都已经听说过这个组件了,但这个组件到底是个什么,如何去使用他呢,且听我讲来. 以下部分资料来自官网(官网才是王道,其他都是浮 ...