Tab View的多种实现方法 .

 

一、引言

标签控件(Tab Control)是VC++编程中经常使用的控件之一,它允许在单个对话框或窗口中设置多个页面,每个页面代表一组控件。当某个页面的标签被选中时,该页 面内的控件就会被显示出来。标签控件使得在有限的窗口空间内可以显示更多的信息,而且分类清晰。同时,VC++提供了以文档/视图 (Document/View)结构方式开发应用程序的简单方法,在文档中保存数据,在视图中显示数据。无论是在SDI还是MDI的程序中,每个文档可以 对应一个或多个是视图,但常常在显示数据时,需要将同一组数据用不同的视图显示,如列表视图、树型视图等,或者用一个视图显示一部分数据,用另一个视图显 示另一部分数据,并且希望能在同一个显示区显示,在需要时进行切换。将标签控制运用到多视图的切换中,就形成了Tab View。

通过上面的分析,我们不难发现,实现一个Tab View主要要完成以下两方面的工作:

   · 实现一个标签窗口。它要具有绘制窗口、响应用户选择、判断处理用户选择等功能。本文对Tab View 实现方法的分类就是根据标签窗口不同划分的。

   · 多个视图之间的切换。根据标签窗口判断用户选择的结果,从多个视图中选择一个,在显示区中显示。

本文分析和总结了三种Tab View的实现方法:

1)利用CTabCtrl控件实现Tab View.

2)利用CSheetCtrl标签选择窗口实现Tab View.

3)利用静态分割窗口实现Tab View.

二、CTabCtrl控件实现Tab View

CTabCtrl是MFC类库中定义的标准控件类,通过对消息TCN-SELCHANGE的处理以及运用函数GetCurSel()、 SetCurSel()等,可以很好地完成响应、判断和设置标签控制的工作,因此利用CTabCtrl控件实现Tab View是较容易的方法。

1.实现的主要类

//要切换显示的视窗口类

class CMyView1 : public CListView

class CMyView2 : public CView

     //派生的标签控件类

class CViewTabCtrl : public CTabCtrl

     //定义了Tab view的主窗口

class CTabCtrlView : public CWnd

{

    protected:

       CViewTabCtrl m_TabCtl;

    …

}

     class CMainFrame : public CFrameWnd

     {

              CTabCtrlView m_TabView;

         …

      }

2.窗口之间的父子关系以及位置关系

      下述代码确定各窗口之间的位置关系。

      void CTabCtrlView::RecalcLayout()

      {    …

          CRect rect;

          // CTabCtrlView窗口的客户区大小

          GetClientRect(&rect);

          m_TabCtl.RecalcLayout(rect, pWnd);

          …

      }

      void CViewTabCtrl::RecalcLayout(CRect & rect, CWnd * wnd)

      {

          //标签控件占据CTabCtrlView窗口的客户区

          SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left,

                       rect.bottom - rect.top, SWP_NOZORDER);

          //调整要显示的视窗口位置,使其占据标签控件的显示区

          AdjustRect(FALSE, &rect);

          wnd->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left,

                            rect.bottom - rect.top, SWP_NOZORDER);

      }

3.多个视之间切换的实现

视的切换主要完成下面的工作:

     // 步骤1:设置当前活动的子窗口的ID

     CView* pOldActiveView = GetActiveView();

     ::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, m_nCurrentExample);

     // 步骤2:生成一个新的与所选择的视窗口对应的运行时类

     CRuntimeClass* pNewViewClass;

     switch (nViewID)// nViewID各个视图的标识

     {

         case ID_MYVIEW1:

             pNewViewClass = RUNTIME_CLASS(CMyView1);

             break;

         case ID_MYVIEW2:

             pNewViewClass = RUNTIME_CLASS(CMyView2);

             break;

          default:

            ASSERT(0);

            return;

     }

     // 步骤3:准备新视图类的相关上下文,创建新的视

     CCreateContext Context;

     Context.m_pNewViewClass = pNewViewClass;

     Context.m_pCurrentDoc = GetActiveDocument();

     CView* pNewView = m_TabView.CreateView(pNewViewClass, CSize(100,100), &Context);

if (pNewView != NULL)

{

         // 步骤4:显示新的视图

         pNewView->ShowWindow(SW_SHOW);

         SetActiveView(pNewView);

         …

         // 步骤5:关闭旧的视图

         pOldActiveView->DestroyWindow();

     }

在视图切换过程中,都需要重新生成新视图,关闭旧的视图。但在某些情况下,希望多个视图窗口能够同时存在,在某时刻只显示一个,而隐藏其它的窗口。可以通过定义下面的数据结构和变量,将每次加入的新视图的窗口信息保存。

typedef struct

{

         CWnd *pWnd;   //窗口指针

         char szLabel[32]; //标签窗口对应该视图的字符串

}TCB_ITEM;

//将每次如入的视图信息保存到列表中

CList <TCB_ITEM *,TCB_ITEM *> m_Views;

在切换时,通过函数SetWindowPos()中设置参数SWP_SHOWWINDOW或SWP_HIDEWINDOW来显示选中的新视图,或隐藏旧视图。采用这种方法,使对视图操作更加灵活,可以很方便在Tab View中添加和删除不同视图。

三、CSheetCtrl标签选择窗口实现Tab View

CSheetCtrl不是MFC类库中的类,用它来实现Tab View的方法和上一个方法基本相同。在程序员大本营网站的VC编程源代码集的[其它控制]分类中,” A Tab-like Sheet Ctrl”程序含有该类源代码,但在使用时要将窗口的切换改为视图切换。

1.标签窗口的创建

CSheetCtrl实现的Attach( )函数,是它与外部的接口。在CTabSheetCtrl 中定义CSheetsWnd m_Sheet ,初始化过程中,通过调用m_Sheet.Attach( this)将CSheetCtrl创建为CTabSheetCtrl窗口的子窗口。

BOOL CSheetsWnd::Attach(CWnd * pWndParent, COLORREF rgbBackground)

{

     //确定了标签窗口的大小和位置

     CRect rect = GetRect(pWndParent);

     …

     BOOL bResult = Create( … , rect , …);

     …

     return bResult;

}

CRect CSheetsWnd::GetRect(CWnd* pWndParent)

{

     CRect rect;

     pWndParent->GetClientRect(rect);

     rect.top = rect.bottom - GetSystemMetrics(SM_CYVTHUMB);

     return rect;

}


2.查找所选视图窗口

CSheetCtrl实现了类似于CTabCtrl的功能,如绘制标签窗口、判断用户的选择等。它本身并没有保存任何有关视图的信息,在视图切换时,它通过其父窗口来查找用户所选的视图窗口。

//得到父窗口的第一个的视图子窗口指针函数

CWnd* CSheetsWnd::GetFirstView()

{

     m_pViewFind = GetParent()->GetWindow(GW_CHILD);

     // m_hWnd存放的是CSheetCtrl标签窗口

     //排除CSheetCtrl标签窗口

         while (m_pViewFind && m_pViewFind->m_hWnd == m_hWnd)

              m_pViewFind = m_pViewFind->GetWindow(GW_HWNDNEXT);

         return m_pViewFind;

}   

//得到下一个视图窗口指针函数

CWnd* CSheetsWnd::GetNextView()

{

         if (m_pViewFind)

         {

             m_pViewFind = m_pViewFind->GetWindow(GW_HWNDNEXT);

             while (m_pViewFind && m_pViewFind->m_hWnd == m_hWnd)

                  m_pViewFind = m_pViewFind->GetWindow(GW_HWNDNEXT);

             return m_pViewFind;

         }

         return NULL;

}

按一定的顺序得到所有父窗口(CTabSheetCtrl)的子窗口(CMyView1、CMyView2)指针后,根据每个子窗口的标题所占空间位置,来确定所选择的视图窗口。

//获得第一个视图窗口指针

     CWnd* pChild = GetFirstView();

     while (pChild)

     {

          CRect rect(cx,0,0,0);

          //rect返回绘制该窗口的标题所需的矩形大小

          pDC->DrawText(GetViewTitle(pChild), rect, DEFAULTFORMATDRAWTEXT | DT_CALCRECT);

          rect.top = 0;

          rect.bottom = m_DrawRect.Height();

          if ((aPointX > cx - LRB) && (aPointX   <= cx + rect.Width() + LRB))// aPointX鼠标位置的横坐标

                 break;//找到所选视图

          //获得下一个视图窗口的指针

          pChild = GetNextView();

          int next = rect.Width() + 6 + LRB;

          cx += next;

      }

四、静态分割窗口实现Tab View


用静态分割窗口CSplitterWnd实现Tab View,其主要的设计思想是通过分割窗口,使用splitter窗口的Pane(0,0)作为切换视的显示区,Pane(0,1)显示类似图3的高级标 签窗口CWndTab。CSplitterWnd窗口完成了上面两种方法中CTabCtrlView和CTabSheetView的工作,作为视的窗口和 标签窗口的容器。此方法的源代码,在程序员大本营网站也有。

五、结束语

笔者通过分析了多个相关程序的源代码,并且在实际编程过程中,根据需要实现了自己的Tab View。在此简要地总结了三种实现Tab View 的方法,希望对读者的编程能有所帮助。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值