VS/MFC编程入门之三十一(常用控件:标签控件Tab Control )

时间:2024-04-03 07:42:22

 

Tab Control,也可以称为选项卡控件。

       标签控件简介

       标签控件也比较常见。它可以把多个页面集成到一个窗口中,每个页面对应一个标签,用户点击某个标签时,它对应的页面就会显示。

       使用标签控件我们可以同时加载多个有关联的页面,用户只需点击标签即可实现页面切换,方便灵活的进行操作。每个标签除了可以显示标签文本,还可以显示图标。

       标签控件相当于是一个页面的容器,可以容纳多个对话框,而且一般也只容纳对话框,所以我们不能直接在标签控件上添加其他控件,必须先将其他控件放到对话框中,再将对话框添加到标签控件中。最终我们点击标签切换页面时,切换的不是控件的组合,而是对话框。

       标签控件的通知消息

       在对标签控件进行一些操作,比如点击标签时,标签控件也会向父窗口发送一些通知消息。我们可以为这些通知消息添加处理函数,实现各种功能。标签控件的主要通知消息及含义如下所示:

       TCN_SELCHANGE:通知父窗口控件的标签选择项已经改变
       TCN_SELCHANGING 通知父窗口控件的标签选择项正在改变
       TCN_KEYDOWN:通知父窗口在控件范围内键盘被按下
       TCN_GETOBJECT:具有TCS_EX_REGISTERDROP扩展特性并且对象被拖动时的通知消息
       TCN_FOCUSCHANGE:通知父窗口控件的按钮聚焦已经改变
       NM_CLICK:通知父窗口用户在控件区域范围内点击了鼠标左键
       NM_RCLICK:通知父窗口用户在控件区域范围内点击了鼠标右键
       NM_RELEASEDCAPTURE:通知父窗口在控件区域范围内释放鼠标捕获消息

       标签控件的相关结构体

       标签控件在使用中也有一些相关的结构体经常用到,主要以下几个:

       1. TCITEMHEADER结构体

       该结构体用来指定或获取标签控件本身的属性。用在TCM_INSERTITEM、TCM_GETITEM和TCM_SETITEM消息中。

C++代码

  1. typedef struct tagTCITEMHEADER {      
  2.     UINT mask;   // 掩码,可以为TCIF_IMAGE(iImage成员有效)、TCIF_RTLREADING、TCIF_TEXT(pszText成员有效)   
  3.     UINT lpReserved1;   // 预留   
  4.     UINT lpReserved2;   // 预留   
  5.     LPTSTR pszText;     // 标签文本字符串   
  6.     int cchTextMax;      
  7.     int iImage;         // 图标在标签控件图像序列中的索引   
  8. } TCITEMHEADER, *LPTCITEMHEADER;   

       2. TCITEM结构体

       该结构体用来指定或获取标签页的属性。用在TCM_INSERTITEM、TCM_GETITEM和TCM_SETITEM消息中。

C++代码

  1. typedef struct tagTCITEM {     
  2.     UINT mask;  // 掩码,可以是TCIF_IMAGE(iImage成员有效)、TCIF_PARAM(lParam成员有效)、TCIF_RTLREADING、TCIF_STATE、TCIF_TEXT(pszText成员有效)  
  3. #if (_WIN32_IE >= 0x0300)   
  4.     DWORD dwState;   
  5.     DWORD dwStateMask;   
  6. #else   
  7.     UINT lpReserved1;   
  8.     UINT lpReserved2;   
  9. #endif   
  10.     LPTSTR pszText;   
  11.     int cchTextMax;   
  12.     int iImage;   
  13.     LPARAM lParam;     // 与标签页关联的32位数据   
  14. } TCITEM, *LPTCITEM;  

       3. TCHITTESTINFO结构体

       该结构体包含了鼠标单击测试的信息。

C++代码

  1. typedef struct tagTCHITTESTINFO {   
  2.     POINT pt;  // 鼠标点击测试的客户区坐标   
  3.     UINT flags; // 接收点击测试的结果。有以下几种:TCHT_NOWHERE(坐标点不在标签上)、TCHT_ONITEM(坐标点在标签上但不在标签文本或图标上)、TCHT_ONITEMICON(坐标点在标签图标上)、TCHT_ONITEMLABEL(坐标点在标签文本上)   
  4. } TCHITTESTINFO, *LPTCHITTESTINFO;  

       4. NMTCKEYDOWN结构体

       该结构体包含了标签控件中键盘按下的相关信息。主要用在TCN_KEYDOWN通知消息中。

C++代码

  1. typedef struct tagNMTCKEYDOWN {   
  2.     NMHDR hdr;   
  3.     WORD wVKey;   
  4.     UINT flags;   
  5. } NMTCKEYDOWN;  

 

标签控件的创建

       MFC为标签控件的操作提供了CTabCtrl类。

       与之前的控件类似,创建标签控件可以在对话框模板中直接拖入Tab Control,也可以使用CTabCtrl类的Create成员函数创建。Create函数的原型如下:

virtual BOOL Create(
  DWORD dwStyle,
  const RECT& rect,
  CWnd* pParentWnd,
  UINT nID 
);

       参数dwStyle为标签控件的风格,rect为标签控件的位置和大小,pParentWnd为指向标签控件父窗口的指针,nID指定标签控件的ID。这里还是要具体说下dwStyle,下面列出了几种主要的控件风格:

       TCS_BUTTONS:标签(控件上部用来选择标签页的位置)外观为按钮风格,且整个控件周围没有边框。

       TCS_FIXEDWIDTH :所有标签具有相同的宽度。

       TCS_MULTILINE:标签以多行显示,如果需要,可以显示所有标签。

       TCS_SINGLELINE:只显示一行标签,用户可以滚动着看其他标签。

       TCS_TABS:标签以普通标签样式显示,且整个控件周围有边框。

       如果想了解标签控件的所有风格,可以查阅MSDN。

       CTabCtrl类的主要成员函数

       int GetCurSel( ) const;

       获取标签控件中当前选择标签的索引。如果成功则返回选择标签的索引,否则返回-1。

       BOOL GetItem(int nItem,TCITEM* pTabCtrlItem) const;

       获取标签控件中某个标签的信息。参数nItem为标签索引,pTabCtrlItem为指向TCITEM结构体的指针,用来接收标签信息。若获取成功返回TRUE,否则返回FALSE。

       int GetItemCount( ) const;

       获取标签控件中标签的数量。

       int SetCurSel(int nItem);

       在标签控件中选择某标签。参数nItem为要选择的标签的索引。如果成功则返回之前选择标签的索引,否则返回-1。

       BOOL SetItem(int nItem,TCITEM* pTabCtrlItem);

       设置某标签的所有或部分属性。参数nItem为标签的索引,pTabCtrlItem为指向TCITEM结构体的指针,包含了新的标签属性。成功则返回TRUE,否则返回FALSE。

       BOOL DeleteAllItems( );

       删除标签控件中所有标签。

       BOOL DeleteItem(int nItem);

       删除标签控件中的某个标签。参数nItem为要删除标签的索引。

       LONG InsertItem(int nItem,LPCTSTR lpszItem);

       在标签控件中插入新的标签。参数nItem为新标签的索引,lpszItem为标签文本字符串。如果插入成功则返回新标签的索引,否则返回-1。

       标签控件的应用实例

       最后依然给大家写一个简单的实例,说明CTabCtrl类的几个成员函数及标签控件通知消息等的使用方法。

       此实例实现的功能:在一个标签控件中加入两个标签页,标签文本分别为“西南交通大学”和“西安交通大学”,点击不同的标签显示不同的标签页。下面是具体实现步骤:

       1. 创建一个基于对话框的MFC工程,名称设置为“Example31”。

       2. 在自动生成的对话框模板IDD_EXAMPLE31_DIALOG中,删除“TODO: 在此处放置对话框控件.”静态文本框、“确定”按钮和“取消”按钮。添加一个Tab Control控件,并为其关联一个CTabCtrl类型的控件变量m_tab,在“资源视图”中点击Example31.rc选择“添加资源”,在左侧区域选择bitmap,点击右侧导入,分别插入西南交通大学和西安交通大学校徽图片,插入成功后再资源视图中会显示Bitmap文件夹,里面包含IDB_BITMAP1和IDB_BITMAP2两个文件。

       3. 创建两个新的对话框,ID分别设为IDD_SWJTU_DIALOG、IDD_XAJTU_DIALOG,两者都将Border属性设为None,Style属性设为Child。在对话框模板IDD_SWJTU_DIALOG中加入一个图片控件Picture Control,设置图片控件的Type属性为Bitmap,在image属性中选择IDB_BITMAP1,并为其生成对话框类CSwjtuDlg;在对话框模板IDD_XAJTU_DIALOG中加入一个图片控件Picture Control,设置图片控件的Type属性为Bitmap,在image属性中选择IDB_BITMAP2,并为其生成对话框类CXajtuDlg。

       4. 在“Example31Dlg.h”文件中包含“SWJTUDlg.h”和“XAJTUDlg.h”两个头文件,然后继续在“Example31Dlg.h”文件中为CExample31Dlg类添加两个成员变量:

CSWJTUDlg swjtu;
CXAJTUDlg xajtu;

 

       5.  在CExample31Dlg对话框初始化时,我们也初始化标签控件。修改CExample31Dlg::OnInitDialog()函数如下:

 
  1. BOOL CExample31Dlg::OnInitDialog()

  2. {

  3. CDialogEx::OnInitDialog();

  4.  
  5. // 将“关于...”菜单项添加到系统菜单中。

  6.  
  7. // IDM_ABOUTBOX 必须在系统命令范围内。

  8. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

  9. ASSERT(IDM_ABOUTBOX < 0xF000);

  10.  
  11. CMenu* pSysMenu = GetSystemMenu(FALSE);

  12. if (pSysMenu != NULL)

  13. {

  14. BOOL bNameValid;

  15. CString strAboutMenu;

  16. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);

  17. ASSERT(bNameValid);

  18. if (!strAboutMenu.IsEmpty())

  19. {

  20. pSysMenu->AppendMenu(MF_SEPARATOR);

  21. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

  22. }

  23. }

  24.  
  25. // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动

  26. // 执行此操作

  27. SetIcon(m_hIcon, TRUE); // 设置大图标

  28. SetIcon(m_hIcon, FALSE); // 设置小图标

  29.  
  30. // TODO: 在此添加额外的初始化代码

  31. CRect tabRect; // 标签控件客户区的位置和大小

  32.  
  33. m_tab.InsertItem(0, _T("西南交通大学")); // 插入第一个标签“西南交通大学”

  34. m_tab.InsertItem(1, _T("西安交通大学")); // 插入第二个标签“西南交通大学”

  35. swjtu.Create(IDD_SWJTU_DIALOG, &m_tab); // 创建第一个标签页

  36. xajtu.Create(IDD_XAJTU_DIALOG, &m_tab); // 创建第二个标签页

  37.  
  38. m_tab.GetClientRect(&tabRect); // 获取标签控件客户区Rect

  39. // 调整tabRect,使其覆盖范围适合放置标签页

  40. tabRect.left += 1;

  41. tabRect.right -= 1;

  42. tabRect.top += 25;

  43. tabRect.bottom -= 1;

  44. // 根据调整好的tabRect放置swjtu子对话框,并设置为显示

  45. swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);

  46. // 根据调整好的tabRect放置xajtu子对话框,并设置为隐藏

  47. xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);

  48.  
  49. return TRUE; // 除非将焦点设置到控件,否则返回 TRUE

  50. }

       6. 运行程序,查看结果,这时我们发现切换标签时,标签页并不跟着切换,而总是显示CJzmDlg对话框。

       7. 我们要实现的是标签页的切换效果,所以还要为m_tab标签控件的通知消息TCN_SELCHANGE添加处理函数,并修改如下:

 
  1. void CExample31Dlg::OnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)

  2. {

  3. // TODO: 在此添加控件通知处理程序代码

  4. CRect tabRect; // 标签控件客户区的Rect

  5.  
  6. // 获取标签控件客户区Rect,并对其调整,以适合放置标签页

  7. m_tab.GetClientRect(&tabRect);

  8. tabRect.left += 1;

  9. tabRect.right -= 1;

  10. tabRect.top += 25;

  11. tabRect.bottom -= 1;

  12.  
  13. switch (m_tab.GetCurSel())

  14. {

  15. // 如果标签控件当前选择标签为“西南交通大学”,则显示swjtu对话框,隐藏xajtu对话框

  16. case 0:

  17. swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);

  18. xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);

  19. break;

  20. // 如果标签控件当前选择标签为“西安交通大学”,则隐藏swjtu对话框,显示xajtu对话框

  21. case 1:

  22. swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);

  23. xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);

  24. break;

  25. default:

  26. break;

  27. }

  28. *pResult = 0;

  29. }

       8. 再运行程序,最终的标签页切换效果如下面两图:

VS2013/MFC编程入门之三十一(常用控件:标签控件Tab Control )

VS2013/MFC编程入门之三十一(常用控件:标签控件Tab Control )

       本节主要对标签控件Tab Control进行介绍,并且通过一个实例对标签控件进行操作,以便熟悉标签控件Tab Control,同时在此实例中对图片控件Picture Control进行了使用,方便大家复习以前的内容。