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

本文实例讲述了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 的方法,希望对读者的编程能有所帮助。

时间: 2024-10-07 21:20:54

Visual C++中Tab View的多种实现方法_C 语言的相关文章

C++将CBitmap类中的图像保存到文件的方法_C 语言

本文实例讲述了C++将CBitmap类中的图像保存到文件的方法.分享给大家供大家参考.具体实现方法如下: 使用下面的代码,可以把CBitmap类中的图像保存到图像文件中.支持格式:BMP.JPG.GIF和PNG. void SaveBitmap(CString strFilePath, CBitmap Bitmap) { if ( Bitmap.m_hObject ) { CImage imgTemp; // CImage是MFC中的类. imgTemp.Attach(Bitmap.operat

C++中sting类的简单实现方法_C 语言

String 在C++的学习生涯我中发现String类的功能十分强大,所以我们是很有必要模拟实现它的,况且在面试的时候模拟实现一个String类也是面试官经常会考的,但是因为外界因素的限制我们是不可能模拟的和库里的string一致的(C++库里的string功能更强大),所以今天我们只模拟实现string的基本功能-构造函数,拷贝构造函数,析构函数,赋值运算符重载,运算符+=的重载,运算符[]的重载,c_str(得到一个C风格的字符指针,可操作字符串),Size,Push_Back,Insert

c语言中字符串分割函数及实现方法_C 语言

1.问题引入 自己在写一个linux下的模拟执行指令的时候,遇到了输入"cat a.c",要将该字符串分解成cat和a.c两个单独的字符串,虽然知道有strtok的存在,但是想自己尝试写一下,于是就自己写了一个,不过总是遇到这样或那样的问题,虽然最后调通了,不过确浪费了不少时间:后来作业交上去以后又仔细阅读了strtok函数,发现原来linux下已经改成strsep,所有在这里就写一下自己所走的过程. 2.自己写的字符串分割函数:用于分割指令,比如cat a.c最后会被分割成cat和a

c++ 构造函数中调用虚函数的实现方法_C 语言

我们知道:C++中的多态使得可以根据对象的真实类型(动态类型)调用不同的虚函数.这种调用都是对象已经构建完成的情况.那如果在构造函数中调用虚函数,会怎么样呢? 有这么一段代码: class A { public: A ():m_iVal(0){test();} virtual void func() { std::cout<<m_iVal<<' ';} void test(){func();} public: int m_iVal; }; class B : public A {

c++中template对字符串的处理方法_C 语言

C++中的Template作用是把仅类型不同但功能相似的函数合并在一起,但是有时候template中的函数并不能满足所有的类型调用.如下所示: template <class Kty> inline int hash_wrap(const Kty& k) { return (int)k; } 所有的数字类型使用该模板都没有问题,但是string类型却不行,因为不支持有string到int的类型转换(编译过程中).这样我们就需要在该模板外添加一个对string类型的支持,代码如下: te

浅析c#中WebBrowser控件的使用方法_C 语言

首先先来简单介绍一下webbrowser控件,这个控件是可以实现在form窗体中添加网页内容的.如图,我在form中加入了百度api,(百度地图api调用博客里有讲) 使用这个控件其实很简单 (1)第一步只要在form_load中输入 复制代码 代码如下: webBrowser1.Navigate(Application.StartupPath + " /map.html");//引号中为网页代码存放地址,注意要用相对地址不用绝对地址,这样才有可移植性,把网页放到程序的debug目录下

解析如何在C语言中调用shell命令的实现方法_C 语言

 1.system(执行shell 命令)相关函数 fork,execve,waitpid,popen表头文件 #include<stdlib.h>定义函数 int system(const char * string);函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-cstring来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程.在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会

详解C++程序中定义struct结构体的方法_C 语言

什么是结构体?简单的来说,结构体就是一个可以包含不同数据类型的一个结构,它是一种可以自己定义的数据类型,它的特点和数组主要有两点不同,首先结构体可以在一个结构中声明不同的数据类型,第二相同结构的结构体变量是可以相互赋值的,而数组是做不到的,因为数组是单一数据类型的数据集合,它本身不是数据类型(而结构体是),数组名称是常量指针,所以不可以做为左值进行运算,所以数组之间就不能通过数组名称相互复制了,即使数据类型和数组大小完全相同. 结构体的定义 定义结构体使用struct修饰符,例如: struct

C++中简单读写文本文件的实现方法_C 语言

代码如下所示: 复制代码 代码如下: #include "stdafx.h"#include <iostream>#include <fstream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ //写入文件 ofstream ofs;  //提供写文件的功能 ofs.open("d:\\com.txt",ios::trunc); //trunc打开文件时,清空已存在的文件