Visual C++中Tab View的多种实现方法

本文实例讲述了Visual C++中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)

相关推荐

  • C++ CTreeview的checkbox使用方法

    1. 消息事件 (1)鼠标点击当前ITEM的CHECKBOX:引发NM_CLICK事件并传递TVHT_ONITEMSTATEICON.    (2)鼠标点击当前ITEM的TEXT:引发NM_CLICK事件.    (3)鼠标点击新ITEM的CHECKBOX:引发TVN_SELCHANGED事件.NM_CLICK事件并传递TVHT_ONITEMSTATEICON.    (4)鼠标点击新ITEM的TEXT:引发NM_CLICK事件.TVN_SELCHANGED事件. 2. 消息事件总结 点击ITE

  • VC实现图片拖拽及动画的实例

    基础知识 1.PictureBox控件的使用 2.加载位图文件 1.通过文件路径获得位图句柄 复制代码 代码如下: //获得位图句柄  void CMovePictureDlg::GetHandleFromPath(CString path)  {      hBitmap= (HBITMAP)::LoadImage(AfxGetInstanceHandle(),path,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);//创建位图句柄

  • VC++中图像处理类CBitmap的用法

    VC++中图像处理类CBitmap的用法 class CBitmap : public CGdiObject { DECLARE_DYNAMIC(CBitmap) public: static CBitmap* PASCAL FromHandle(HBITMAP hBitmap); // Constructors CBitmap(); BOOL LoadBitmap(LPCTSTR lpszResourceName); BOOL LoadBitmap(UINT nIDResource); BOO

  • 在Visual Studio中用C++语言创建DLL动态链接库图文教程

    什么是DLL(动态链接库)? DLL是一个包含可由多个程序同时使用的代码和数据的库.例如:在Windows操作系统中,Comdlg32 DLL执行与对话框有关的常见函数.因此,每个程序都可以使用该DLL中包含的功能来实现"打开"对话框.这有助于促进代码重用和内存的有效使用.这篇文章的目的就是让你一次性就能了解和掌握DLL. 为什么要使用DLL(动态链接库)? 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可以将它构造成相对独立的功能模块并在之后的项目中重复

  • Visual C++程序设计中Windows GDI贴图闪烁的解决方法

    本文实例讲述了Visual C++程序设计中Windows GDI贴图闪烁的解决方法.分享给大家供大家参考.具体如下: 一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一: 如果熟悉显卡原理的话,调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕 上只是写到了显存里,而显卡每隔一段时间把显存的内容输出到屏幕上,这就是刷新周期. 一般显卡的刷新周期是 1/80秒左右,具体数字可以自己设置的. 这样

  • c++ builder TreeView控件节点遍历代码

    复制代码 代码如下: void __fastcall TForm1::GetRootNodes(TTreeView *DestTreeView)//得到所有根节点{        TTreeNode *vNode = NULL;        vNode = DestTreeView->Items->GetFirstNode();        while(vNode)        {                ShowMessage(vNode->Text);//处理查找到的根节

  • VC++实现View内容保存为图片的方法

    本文实例讲述了VC++实现View内容保存为图片的方法.分享给大家供大家参考,具体如下: 我们在单文档应用程序中,经常需要将View中的内容保存为各种格式的图片文件,以便打印.乍一看,可能不知道从哪里下手,其实主要就是用到Bitmap的save方法,如: HDC hmemDC = ::CreateCompatibleDC( hdc ); HBITMAP hBmp = ::CreateCompatibleBitmap( hdc, destRect.Width(),destRect.Height()

  • Visual C++中Tab View的多种实现方法

    本文实例讲述了Visual C++中Tab View的多种实现方法,分享给大家供大家参考.具体如下: 一.引言 标签控件(Tab Control)是VC++编程中经常使用的控件之一,它允许在单个对话框或窗口中设置多个页面,每个页面代表一组控件.当某个页面的标签被选中时,该页 面内的控件就会被显示出来.标签控件使得在有限的窗口空间内可以显示更多的信息,而且分类清晰.同时,VC++提供了以文档/视图 (Document/View)结构方式开发应用程序的简单方法,在文档中保存数据,在视图中显示数据.无

  • Visual Style中的shellstyle.dll文件修改方法

    Visual Style中的shellstyle.dll文件修改  2007-3-8 11:25:00  作者: Silencer  shellstyle.dll修改 *部分内容参考自whistl3r的Shellstyle Tutorial 预备知识 1.shellstyle.dll的结构 UIFiles: UIFile1:定义窗体及任务列表样式 UIFile2:定义控制面板样式 Resources:资源文件列表 10,11,12:音乐文件夹 13,14,15:图片文件夹 16,17,18:查找

  • Visual Studio中的jQuery智能提示设置方法

    1.VS2008 1) 安装VS2008 SP1补丁,下载链接.SP1补丁提供Javascript脚本库的智能提示功能. 2) 安装KB958502补丁,下载链接.KB958502补丁支持-vsdoc.js智能提示文件的关联功能,更多说明. 3) 下载jQuery原文件及-vsdoc.js文件,并通过相同的文件名前缀进行关联. 例,下载jquery-1.2.6.js和jquery-1.2.6-vsdoc.js, 拷贝到本地目录并引入到Web应用程序或Web站点的工程中. 现在你只需要添加jque

  • 灵活掌握asp.net中gridview控件的多种使用方法(上)

    灵活使用asp.net中gridview控件的方法有很多种,本文内容很富,希望大家都能有所收获. 1.GridView无代码分页排序: 效果图: 小提示: 1.AllowSorting设为True,aspx代码中是AllowSorting="True": 2.默认1页10条,如果要修改每页条数,修改PageSize即可,在aspx代码中是PageSize="12". 3.默认的是单向排序的,右击GridView弹出"属性",选择AllowSort

  • Android App开发中自定义View和ViewGroup的实例教程

    View Android所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top表示View相对于它的parent View的起点,width,height表示View自己的宽高,通过这4个字段就能确定View在屏幕上的位置,确定位置后就可以开始绘制View的内容了. View绘制过程 View的绘制可以分为下面三个过程: Measure View会先做一次测量,算出自己需要占用多大的面积.View的Measure过程给我们暴露了一个

  • Visual Studio 中自定义代码片段的方法

    第一步.打开 Visual Studio Code,按Ctrl + Shift + P,输入:Configure User Snippets,选择 Preferences:Configure User Snippets. 第二步.回车后,选择一个配置文件,或者新建一个配置文件,我选择的是 HTML 配置文件. 第三步.按照示例添加吧,JSON 格式. 我增加了两个,一个是 style 的,一个是 script 的,如下: { "Add style tag": { "prefi

  • 在 Visual Studio 中查看反汇编代码

    在源代码中设置断点,然后进行点击调试 若要启用反汇编窗口,请在工具>选项(或工具> 选项>调试下,选择启用地址级调试. 若要在调试期间打开反汇编窗口,请选择窗口>反汇编或按 Alt+8 . 除汇编指令外,反汇编窗口还可显示下列可选信息: 每条指令所在的内存地址 对于本机应用程序,它是实际内存地址. 对于 Visual Basic 或 C#,它是距离函数开头的偏移量. 程序集代码派生于的源代码. 代码字节,即实际计算机或 MSIL 指令的字节表示形式. 内存地址的符号名. 对应于源代

  • 实例讲解JavaScript的Backbone.js框架中的View视图

    Backbone 中的 View 用来反映你 app 中 Model 的模样.它们会监听事件并作出相应的反应. 接下来的教程我不会告诉你如何把 Model 和 Collection 绑定到 View 上,而是主要讨论 View 是如何使用 javascript 模板库的,尤其是 Underscore.js's _.template. 这里我们使用 jQuery 来操作 DOM 元素,当然你也可以使用其他的库,例如 MooTools 或者 Sizzle,但是 Backbone 的官方文档推荐我们使

  • Android中通过view方式获取当前Activity的屏幕截图实现方法

    此方法是通过view的方式获取当前activity的屏幕截图,并不是framebuffer的方式,所以有一定的局限性.但是这种方法相对简单,容易理解. 首先通过下面的函数获取Bitmap格式的屏幕截图: 复制代码 代码如下: public Bitmap myShot(Activity activity) { // 获取windows中最顶层的view View view = activity.getWindow().getDecorView(); view.buildDrawingCache()

  • 灵活掌握asp.net中gridview控件的多种使用方法(下)

    继续上篇文章的学习<灵活掌握asp.net中gridview控件的多种使用方法(上)>,在此基础上巩固gridview控件的操作使用,更上一层楼. 11.GridView实现用"..."代替超长字符串: 效果图: 解决方法:数据绑定后过滤每一行即可 for (int i = 0; i <= GridView1.Rows.Count - 1; i++) { DataRowView mydrv; string gIntro; if (GridView1.PageIndex

随机推荐