您的位置:首页 > 其它

视图切换相关

2016-06-03 14:40 225 查看
1、得到与pDoc相关联的view

CCView1Doc *pDoc = (CCView1Doc *)GetActiveDocument();

CCView1View *pCADView = NULL;

if (pDoc != NULL)

{
POSITION posView = pDoc->GetFirstViewPosition(); 
while(posView)
{      
CView *pView = (CView *)pDoc->GetNextView(posView);

}


2、View与pPoc相关联

CCView1Doc *pDoc = (CCView1Doc *)GetActiveDocument();

CCreateContext context; 

context.m_pCurrentDoc=pDoc ; 

pNewActiveView->Create(NULL,NULL,WS_CHILD | WS_BORDER,CRect(0,0,100,200), CWnd::GetDesktopWindow(),nForm,&context); 

pNewActiveView->Create(NULL,NULL,WS_CHILD | WS_BORDER,CFrameWnd::rectDefault,this,nForm,&context); 

3、SetDlgCtrlID

int SetDlgCtrlID(
int nID
);


The new value to set for the control's identifier.

The
window can be any child window, not only a control in a dialog box. The window cannot be a top-level window.

只是改变控件的ID而已。

4、SetActiveView 

void SetActiveView(
CView* pViewNew,
BOOL bNotify = TRUE
);


框架将自动调用此功能,用户更改焦点到框架窗口中的视图。 可以显式调用 SetActiveView 更改焦点到指定的视图。

5、AFX_IDW_PANE_FIRST: 对于SDI,那么你的view窗口的ID就是这个值。(你在CMainFrame中通过GetDlgItem(AFX_IDW_PANE_FIRST)就能得到你的视图窗口的指针。 对于MDI,那么你的MDI客户区窗口的ID就是这个值。你在CMainFrame中通过GetDlgItem(AFX_IDW_PANE_FIRST)就能得到这个窗口的指针。注意,MDI客户区就是在MDI下,没有打开任何文档时工具条下面的那个窗口。 实际上AFX_IDW_PANE_FIRST是为了解决多个VIEW的情况下消息转发的问题,这是MFC内部使用的一个固定的值,所有当前的活动视图都会切换到AFX_IDW_PANE_FIRST这个ID,主窗口收到的一些消息(比如命令、通知等等消息)会转发给活动视图来处理,框架通过这个ID来定位活动视图。
当在某个SDI应用程序中使用多个视图并支持视图切换时,很容易忽略这点,造成某些消息得不到正确的响应,因此当激活某个视图时也要把这个视图的ID改成AFX_IDW_PANE_FIRST。

6、CView调用delete注意

窗口在关闭的时候会调用一个叫做PostNCDestory()的函数,这个函数的最后一句话是delete    this;

7、视图切换

单文档多视图切换是我在学习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这个函数主要用于视图切换

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

①、获得当前视图类指针和需要转换的视图类指针,如果是第一次使用需要New一个,并且与文档类关联;

②、改变活动视图;

③、显示新视图和隐藏旧视图;

④、设置控件ID;

⑤、调整框架视图。

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

delete pOldActiveView;  //窗口没有关闭操作,故可以释放

RecalcLayout(); //5 



也可以一开始就创建好所有的视图

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

 m_pListCtrlView = new CListCtrlView;
//不需要释放,在最后点击关闭按钮的时候调用PostNCDestory()

 ((CView*) m_pListCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_LISTCTRL, pContext);
 SetActiveView(m_pListCtrlView);

 m_pListCtrlView->ShowWindow(SW_SHOW);

 m_pListCtrlView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

 m_nCurrentViewID = VIEW_LISTCTRL;
 m_pEditCtrlView = new CEditView;

 ((CView*) m_pEditCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_EDIT, pContext);

 m_pEditCtrlView->ShowWindow(SW_HIDE);

 m_pEditCtrlView->SetDlgCtrlID(VIEW_EDIT);
 RecalcLayout();
 return TRUE;

}

void CMainFrame::SwitchToView(UINT nView)

{

 CView* pOldActiveView = GetActiveView();

 CView* pNewActiveView = NULL;
 switch (nView)

 {

 case VIEW_LISTCTRL:

  pNewActiveView = (CView*) m_pListCtrlView;

  break;

 case VIEW_EDIT:

  pNewActiveView = (CView*) m_pEditCtrlView;

  break;

 }
 if (pNewActiveView)

 {

  if (pOldActiveView == pNewActiveView) return;
  SetActiveView(pNewActiveView);

  pNewActiveView->ShowWindow(SW_SHOW);

  pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

  pOldActiveView->ShowWindow(SW_HIDE);

  pOldActiveView->SetDlgCtrlID(m_nCurrentViewID);

  m_nCurrentViewID = nView;
  RecalcLayout();

 }
}


第二部分在分割窗格的一个窗格内实行视图切换

分割窗格的视图切换,我觉得难点是不容易在有限区域进行视图切换。

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、响应主要包括下面几个步骤:

①、首先获得窗格中的当前视图;

②、使用IsKindOf判断这个类是否是将要切换到的类;

③、获得框架长宽和窗格长宽;

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

上面的全部是准备工作,下面才是真正的切换;

④、删除原有视图

⑤、创建当前视图

⑥、调整框架

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

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: