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);

 

}

 

3SwitchToForm这个函数主要用于视图切换

 

在这个函数中主要做以下几个动作:

 

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);

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值