VC编程 2010-12-04 23:20:29 阅读87 评论0 字号:大中小 订阅
在我们开发的工程中,经常要遇到单文档多视的开发,且常常伴有切分窗口的需求.这个切分,通常是静态切分的,比如说,客户窗口的左边是一个控件如outlook风格的抽屉控件,右边是一个视图.通过菜单命令,来改变右边视图.
下面,我以一个例子来说明:
新建一个单文档的工程.文档基类是CDocument
1. 在CmainFrame头文件中,加入成员变量CsplitterWnd m_splitWnd;
在CmainFrame 的cpp文件中,重载OnCreateClient函数
/ / #include ".\YouDoc.h"
//#include ".\YourView1.h"
//#include ".\YourView2.h"
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
//return CFrameWnd::OnCreateClient(lpcs, pContext);
if(!m_SplitWnd.CreateStatic(this,1,2))
{
TRACE("Create splitwnd failure\n");
return -1;
}
//here, add your outlook control
#if 1
// m_XTOutBarCtl是CmainFrame的成员变量,
DWORD dwf = CGfxOutBarCtrl::fDragItems|CGfxOutBarCtrl::fEditGroups
| CGfxOutBarCtrl::fEditItems|CGfxOutBarCtrl::fRemoveGroups
| CGfxOutBarCtrl::fRemoveItems|CGfxOutBarCtrl::fAddGroups
| CGfxOutBarCtrl::fAnimation;
//注意,这是m_XTOutBarCtl的父窗口不是主窗口,也不是m_Splitwnd的右边的视,实际上右//边没有视图,它的父窗口是切分窗口本身. if(!m_XTOutBarCtl.Create(WS_CHILD|WS_VISIBLE,CRect(),&m_SplitWnd,m_SplitWnd.IdFromRowCol(0, 0), dwf))
{
TRACE("Create splitwnd failure\n");
return -1;
}
//init outbar ctrl
...
#endif
VERIFY(m_SplitWnd.CreateView(0,1,RUNTIME_CLASS(CyourView1),CSize(100, 100), pContext));
//这句很得要,我们要得到活动的视.
m_SplitWnd.SetActivePane(0,1);
m_SplitWnd.SetColumnInfo(0,150,10);
m_SplitWnd.RecalcLayout();
return 1;
}
2.通过classwizard,向工程中添加一个视类Cview2,在示例工程中,其基类为CformView
在菜单中增加两个命令:testView1,testView2,其ID分别为ID_VIEW_SWITCH1, ID_VIEW_SWITCH2
及处理函数
响映其消息:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND(ID_VIEW_SWITCH1, OnViewSwitch1)
ON_COMMAND(ID_VIEW_SWITCH2,OnViewSwitch2)
//ON_COMMAND_RANGE(ID_VIEW_SWITCH1,ID_VIEW_SWITCH2, OnViewSwitch)
END_MESSAGE_MAP()
其消息处理为:
void CMainFrame::OnViewSwitch1()
{
// TODO: Add your command handler code here
CRuntimeClass *pNewViewClass = RUNTIME_CLASS(CyourView1);
CView *pActiveView = GetActiveView();
if(pActiveView->IsKindOf(pNewViewClass))
{
pNewViewClass = RUNTIME_CLASS(CyourView2);
judgeViewID(pNewViewClass);
}
}
void CMainFrame::OnViewSwitch2()
{
// TODO: Add your command handler code here
CRuntimeClass *pNewViewClass = RUNTIME_CLASS(CyourView2);
CView *pActiveView = GetActiveView();
if(pActiveView->IsKindOf(pNewViewClass))
{
pNewViewClass = RUNTIME_CLASS(CyourView1);
judgeViewID(pNewViewClass);
}
}
judgeViewID(pNewViewClass)是处理切换视的函数,其实现为:
UINT CMainFrame::judgeViewID(CRuntimeClass *pNewViewClass)
{
CView *pOldActiveView = (CView *)GetActiveView();
if(pOldActiveView->IsKindOf(pNewViewClass))
{
return 1;
}
//ASSERT(pSplitter->IsChildPane(pOldActiveView,row,col));
CRect viewRect;
CDocument *pDoc = this->GetActiveDocument();
//这个判断是非常重要的,我们要自已把是非删除文档置为FALSE,
//否则,当我们切换成功后,当View在onDraw时,会得不到document,
//会产生异常,导致失败!
if(pDoc)
{
//when all views been destroy ,dont close document
pDoc->m_bAutoDelete = FALSE;
}
pOldActiveView->GetWindowRect(&viewRect);
//如果这里不destroywindow,当我们createview时,splitwnd会检测到其窗口存在,
//而导致创建视失败.
//就是这句CWnd *pwnd = m_SplitWnd.GetDlgItem(m_SplitWnd.IdFromRowCol(0, 1));
//当创建视时,它先判断pwnd == NULL
//而如果在前面不置文档的m_bAutoDelete为FALSE,当destroywondow()视时,文档发现自己//的视类没有了,会把自己关掉,导致其维护的m_viewList的头指针为非法值了,产生意想不//到的fata error.
pOldActiveView->DestroyWindow();
if(pDoc)
{
//还原其内核的参数值
pDoc->m_bAutoDelete = true;
}
CCreateContext context;
context.m_pCurrentDoc = pDoc;
context.m_pNewViewClass = pNewViewClass;
CWnd *pwnd = m_SplitWnd.GetDlgItem(m_SplitWnd.IdFromRowCol(0, 1));
if(!m_SplitWnd.CreateView(0,1,pNewViewClass,viewRect.Size(),&context))
{
return 0;
}
m_SplitWnd.SetColumnInfo(0, 120, 10);
//pSplitter->SetColumnInfo(1, , 10);
CView *pNewView = (CView *)m_SplitWnd.GetPane(0,1);
if(pNewView->IsKindOf(RUNTIME_CLASS(CETSOFTView)))
{
CDocument *pDoc = this->GetActiveDocument();
}
m_SplitWnd.GetParentFrame()->SetActiveView(pNewView);
m_SplitWnd.RecalcLayout();
return 1;
}