单纯视图之间的切换

单文档多视图切换是我在学习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视图切换大全总结的更多相关文章

  1. MFC中窗口静态分割&视图切换

    目录 窗口静态分割 单个分割器 声明 准备视图 静态分割窗口&添加视图 使视图大小随窗口大小改变 多个分割器 声明 静态分割窗口&添加视图 使视图大小随窗口大小改变 视图切换 视图之间 ...

  2. iOS开发系列--视图切换

    概述 在iOS开发中视图的切换是很频繁的,独立的视图应用在实际开发过程中并不常见,除非你的应用足够简单.在iOS开发中常用的视图切换有三种,今天我们将一一介绍: UITabBarController ...

  3. pushViewController addSubview presentModalViewController视图切换

    1.pushViewController和popViewController来进行视图切换,首先要确保根视图是NavigationController,不然是不可以用的, pushViewContro ...

  4. IOS 视图切换动画

    我在网上找到的这个小方法,被我举一反三使用的屡试不爽.比如用在,当视图需要执行某一方法跳转到新的一个UIView上,从底层渐变浮到最上层.就是一个不错的视觉效果或者当需要类似keyboard的效果从底 ...

  5. UI3_视图切换

    // // ViewController.m // UI3_视图切换 // // Created by zhangxueming on 15/7/3. // Copyright (c) 2015年 z ...

  6. UI2_视图切换ViewController

    // // SubViewController.h // UI2_视图切换 // // Created by zhangxueming on 15/7/3. // Copyright (c) 2015 ...

  7. UI1_ViewController视图切换及Appdelegate

    // // ThirdViewController.h // UI1_ViewController视图切换及Appdelegate // // Created by zhangxueming on 1 ...

  8. UI2_视图切换

    // // ViewController.m // UI2_视图切换 // // Created by zhangxueming on 15/7/1. // Copyright (c) 2015年 z ...

  9. Tabbar视图切换,返回上一视图,添加item

    前面有一篇博文iOS学习之Tab Bar的使用和视图切换 这是在AppDelegate里使用Tabbar,这样的程序打开就是TabbarView了,有时候我们需要给程序做一些帮助页面,或者登录页面,之 ...

随机推荐

  1. ffmpeg显示视频

    项目最近需要实现播放视频功能,这个在上家公司就做过.虽然跟之前的场景不一样,有以前的功底还是很快可以解决,事实也确实如此.在使用DShow处理完视频分割与合并后,继续使用DShow显示视频,很快即完成 ...

  2. 【转】linux下a.out >outfile 2>&1重定向问题

    原文网址:http://blog.chinaunix.net/uid-25909722-id-2912890.html 转自:http://blog.chinaunix.net/space.php?u ...

  3. codedorces 260 div2 A题

    水题,扫描一遍看是否出现价格低质量高的情况. #include<cstdio> #include<string> #include<vector> #include ...

  4. SQL 语句记录

    1.创建一个table @"create table rockTB(myId integer primary key autoincrement not null, time varchar ...

  5. IOS 本地通知UILocalNotification

    //发送通知    UILocalNotification *notification=[[UILocalNotification alloc] init];       if (notificati ...

  6. What do data scientist do?

    What do data scientist do? 1. Define the question 2.Define the ideal data set 3.Determine what data ...

  7. java计时代码

    public class Test{ public static void main(String[] args) { long startMili=System.currentTimeMillis( ...

  8. ubuntu使用问题与解决记录[持续更新]

    1. 添加到计划任务 为脚本增加可执行权限 sudo chmod +x yeelink.sh 将脚本加入cronjob(计划任务) sudo crontab -e 在cornjob文件中添加下面一行, ...

  9. FLEX实现两侧边栏固定中间自适应布局

    <style type="text/css"> #outer{ display: flex; width: 100%; flex-flow: row nowrap; } ...

  10. 轻松突击ThreadLocal

    本文出自 代码大湿 代码大湿 ThreadLocal是用来保存线程的本地变量,可以保证每个线程都有一个自己的变量(包括static变量). 本文所有代码请点击我 1 看个实际场景. 我们要设计一个序列 ...