VS2013/MFC程式設計入門之三十一(常用控制元件:標籤控制元件Tab Control )
前面兩節講了樹形控制元件Tree Control,本節開始講解標籤控制元件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++程式碼- typedefstruct tagTCITEMHEADER {
- UINT mask; // 掩碼,可以為TCIF_IMAGE(iImage成員有效)、TCIF_RTLREADING、TCIF_TEXT(pszText成員有效)
-
UINT
- UINT lpReserved2; // 預留
- LPTSTR pszText; // 標籤文字字串
- int cchTextMax;
- int iImage; // 圖示在標籤控制元件影象序列中的索引
- } TCITEMHEADER, *LPTCITEMHEADER;
2. TCITEM結構體
該結構體用來指定或獲取標籤頁的屬性。用在TCM_INSERTITEM、TCM_GETITEM和TCM_SETITEM訊息中。
C++程式碼- typedefstruct tagTCITEM {
- UINT mask; // 掩碼,可以是TCIF_IMAGE(iImage成員有效)、TCIF_PARAM(lParam成員有效)、TCIF_RTLREADING、TCIF_STATE、TCIF_TEXT(pszText成員有效)
- #if (_WIN32_IE >= 0x0300)
- DWORD dwState;
- DWORD dwStateMask;
- #else
- UINT lpReserved1;
- UINT lpReserved2;
- #endif
- LPTSTR pszText;
- int cchTextMax;
- int iImage;
- LPARAM lParam; // 與標籤頁關聯的32位資料
- } TCITEM, *LPTCITEM;
3. TCHITTESTINFO結構體
該結構體包含了滑鼠單擊測試的資訊。
C++程式碼- typedefstruct tagTCHITTESTINFO {
- POINT pt; // 滑鼠點選測試的客戶區座標
- UINT flags; // 接收點選測試的結果。有以下幾種:TCHT_NOWHERE(座標點不在標籤上)、TCHT_ONITEM(座標點在標籤上但不在標籤文字或圖示上)、TCHT_ONITEMICON(座標點在標籤圖示上)、TCHT_ONITEMLABEL(座標點在標籤文字上)
- } TCHITTESTINFO, *LPTCHITTESTINFO;
4. NMTCKEYDOWN結構體
該結構體包含了標籤控制元件中鍵盤按下的相關資訊。主要用在TCN_KEYDOWN通知訊息中。
C++程式碼- typedefstruct tagNMTCKEYDOWN {
- NMHDR hdr;
- WORD wVKey;
- UINT flags;
- } 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()函式如下:
BOOL CExample31Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”選單項新增到系統選單中。
// IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 設定此對話方塊的圖示。 當應用程式主視窗不是對話方塊時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設定大圖示
SetIcon(m_hIcon, FALSE); // 設定小圖示
// TODO: 在此新增額外的初始化程式碼
CRect tabRect; // 標籤控制元件客戶區的位置和大小
m_tab.InsertItem(0, _T("西南交通大學")); // 插入第一個標籤“西南交通大學”
m_tab.InsertItem(1, _T("西安交通大學")); // 插入第二個標籤“西南交通大學”
swjtu.Create(IDD_SWJTU_DIALOG, &m_tab); // 建立第一個標籤頁
xajtu.Create(IDD_XAJTU_DIALOG, &m_tab); // 建立第二個標籤頁
m_tab.GetClientRect(&tabRect); // 獲取標籤控制元件客戶區Rect
// 調整tabRect,使其覆蓋範圍適合放置標籤頁
tabRect.left += 1;
tabRect.right -= 1;
tabRect.top += 25;
tabRect.bottom -= 1;
// 根據調整好的tabRect放置swjtu子對話方塊,並設定為顯示
swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
// 根據調整好的tabRect放置xajtu子對話方塊,並設定為隱藏
xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
return TRUE; // 除非將焦點設定到控制元件,否則返回 TRUE
}
6. 執行程式,檢視結果,這時我們發現切換標籤時,標籤頁並不跟著切換,而總是顯示CJzmDlg對話方塊。
7. 我們要實現的是標籤頁的切換效果,所以還要為m_tab標籤控制元件的通知訊息TCN_SELCHANGE新增處理函式,並修改如下:
void CExample31Dlg::OnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: 在此新增控制元件通知處理程式程式碼
CRect tabRect; // 標籤控制元件客戶區的Rect
// 獲取標籤控制元件客戶區Rect,並對其調整,以適合放置標籤頁
m_tab.GetClientRect(&tabRect);
tabRect.left += 1;
tabRect.right -= 1;
tabRect.top += 25;
tabRect.bottom -= 1;
switch (m_tab.GetCurSel())
{
// 如果標籤控制元件當前選擇標籤為“西南交通大學”,則顯示swjtu對話方塊,隱藏xajtu對話方塊
case 0:
swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
break;
// 如果標籤控制元件當前選擇標籤為“西安交通大學”,則隱藏swjtu對話方塊,顯示xajtu對話方塊
case 1:
swjtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_HIDEWINDOW);
xajtu.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), SWP_SHOWWINDOW);
break;
default:
break;
}
*pResult = 0;
}
8. 再執行程式,最終的標籤頁切換效果如下面兩圖:
本節主要對標籤控制元件Tab Control進行介紹,並且通過一個例項對標籤控制元件進行操作,以便熟悉標籤控制元件Tab Control,同時在此例項中對圖片控制元件Picture Control進行了使用,方便大家複習以前的內容。如果想了解更多的相關內容,大家可以檢視MSDN。最後還是謝謝各位的關注和支援,歡迎大家留言進行討論學習,謝謝。