窗口切换分割详解

这里写一下窗口的切换于分割。一般这里说的是单文档界面或者多文档界面的各种分割与切换。多文档的作法和单文档没有什么区别,这里就以单文档为例。在本文最后我会列一个分割对话框的例子。这部份内容不是很少,在书上查得到的我就不详细说了。

一般常用的MFC视窗结构是文档/视窗结构(document/view architecture)。有很多人说这个结构浪费不少资源,不够节约。但我觉得作到界面这一级浪费点资源没什么太大问题。只要不漏内存,不影响效率就已经足够好了。何况这是微软最推崇的标准界面。
文档/视窗(document/view architecture)结构主要由四个class组成。document类,view类,framework类和app类。app类是程序的引擎,在MFC中是最不不要关心的一个类。framwork是窗口的框架,在程序运行开始的时候先生成框架,然后是document class,这里是用来存储数据的。然后是view类,用来显示数据同时作数据交换的。单文档界面只有一个document class,但可以有多了view class。至少有一个view class是active的。可以用GetActiveView()得到它的指针。没个和document class 关联的view class都有一个control ID,这个ID是一个整数。如果总共只显示一个view class,这个class的control ID是AFX_IDW_PANE_FIRST,如果同时显示好几个view class就需要用分割器(splitter)割开。class 名字叫CSplitterWnd。CSplitterWnd有两种不同的切割framework的方式。一种叫动态的,用Create()来实现,切的很不理想。没见过多少class用这种切法。真正应用广泛的是静态切割,用CReateStatic实现。当然从名字上就可以看出静态切割的缺点,就是不能动态重新切分。在本文中我会介绍一个可以实现静态切割的程序。被分割器隔开的窗口的Control ID可以通过IdFromRowCol(row, col)函数得到,row和col是窗口的行数和列数。其数值也是在AFX_IDW_PANE_FIRST。也是一个比较大的数字。所以隐藏当前不想显示的view时把他的control ID改成一个1,2,3之类的很小的数就可以了。

基本知识就说这些,肯定不够详细,大家可以参照Visual C++的各种教程找到详细资料。下面开始说一些具体问题了。从单窗口开始。
1。在Framework中显示一个View。通过菜单或按钮切换成不同的view。假设有三种view: CViewA, CViewB,CViewC。用三个常数表示他们不显示时的control ID.

enum eView {ViewA, ViewB, ViewC};
在CMainFrame加上下面一个函数就可以实现不同窗口的切换了。很易懂,唯一没有说的就是CCreateContext context,这是每次Create一个view时必须设定的。其实也就是m_pCurrentDoc这个指向当前document class的指针需要设定,其它的取默认值就可以了。

void CMainFrame::SwitchToView(eView nView)
{
    CView* pOldActiveView = GetActiveView();
    CView* pNewActiveView = (CView*) GetDlgItem(nView);
    if (pNewActiveView == NULL)
    {
        switch (nView)
        {
        case ViewA:
            pNewActiveView = (CView*) new CViewA;
            break;
        case ViewB:
            pNewActiveView = (CView*) new CViewB;
            break;
        case ViewC:
            pNewActiveView = (CView*) new CViewC;
            break;
        }
        CCreateContext context;
        context.m_pCurrentDoc = pOldActiveView->GetDocument();
        pNewActiveView->Create(NULL, NULL, WS_BORDER|WS_CHILD,
            CFrameWnd::rectDefault, this, nView, &context);
        pNewActiveView->OnInitialUpdate();
    }

    SetActiveView(pNewActiveView);
    pNewActiveView->ShowWindow(SW_SHOW);
    pOldActiveView->ShowWindow(SW_HIDE);
    pOldActiveView->SetDlgCtrlID(m_nCurrentView);
    pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
    m_nCurrentView = nView;
    RecalcLayout();
}


2。显示1个,2个或4个窗口。
需要用splitter class,这里就不详细说了,任何Visual C++书上都有。无论是Dynamic的还是Static的。

3。显示1个,2个或4个窗口。同时窗口可以切换。
这里只讲静态窗口的切换,动态的效果不是很好,用户不想切的时候也会自动切。
静态窗口的切换的效果就是Window Explorer那样,左边的目录栏一点右面就跟着变了。这里需要在已有的CSplitterWnd的基础上写一点小小的增强。需要一个切换功能。从CSplitterWnd继承出一个class,例如叫CDynViewSplitter。

BOOL CDynViewSplitter::ReplaceView(int row, int col,CRuntimeClass * pViewClass,SIZE size)
{
  CCreateContext context;
  BOOL bSetActive;
          
  
   // Get pointer to CDocument object so that it can be used in the creation
   // process of the new view
   CDocument * pDoc= ((CView *)GetPane(row,col))->GetDocument();
   CView * pActiveView=GetParentFrame()->GetActiveView();
   if (pActiveView==NULL || pActiveView==GetPane(row,col))
      bSetActive=TRUE;
   else
      bSetActive=FALSE;

    // set flag so that document will not be deleted when view is destroyed
    pDoc->m_bAutoDelete=FALSE;    
    // Delete existing view
   ((CView *) GetPane(row,col))->DestroyWindow();
    // set flag back to default
    pDoc->m_bAutoDelete=TRUE;

    // Create new view                      
  
   context.m_pNewViewClass=pViewClass;
   context.m_pCurrentDoc=pDoc;
   context.m_pNewDocTemplate=NULL;
   context.m_pLastView=NULL;
   context.m_pCurrentFrame=NULL;
  
   CreateView(row,col,pViewClass,size, &context);
  
   CView * pNewView= (CView *)GetPane(row,col);
  
   if (bSetActive==TRUE)
      GetParentFrame()->SetActiveView(pNewView);
  
   RecalcLayout();
   GetPane(row,col)->SendMessage(WM_PAINT);
  
   return TRUE;
}
这里对用完了的view是destroy掉了,处理和第一种不大一样。其它的没什么值得说的。


4。这是个以前没有想过的问题,静态窗口的重新切分,时分时合。由于有了上面两个例子结合一下就可以了。需要知道的是CSplitterWnd在最开始切分窗口CreateStatic的时候不可以切成一行一列,也就是不切。CreateStatic一定要作真正的切割。这给整个问题带来了不少麻烦。好在CSplitterWnd的员程序全都可以读到,只有两千多行。看一看construct之后作的事情的确很多,但desctructor很简单,所以合并之前把自己的CSplitterWnd删掉就可以了。下面是这个例子可以在当窗口CViewA,单窗口CViewB,双窗口CViewMenu/CViewA之间互相切换,在窗窗口的时候还可以实现右边窗口CViewA到CViewB的切换。



5。多个窗口的分割,不只1X1,1X2,2X1,2X2。可以分得十分复杂,比VC IDE上的窗口还多都可以。这时需要用多个Splitter。
6。对话框的切分,没有标准的MFC class,需要自己写一个。
5和6的例子我回头加上。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值