浅谈SDI单文档多视切换方法

 

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_XTOutBarCtlCmainFrame的成员变量,

    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;

}

原文地址:https://www.cnblogs.com/cy163/p/1931316.html