1. 程式人生 > >VS2013/MFC程式設計入門之三十一(常用控制元件:標籤控制元件Tab Control )

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++程式碼
  1. typedefstruct 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. typedefstruct 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. typedefstruct tagTCHITTESTINFO {   
  2.     POINT pt;  // 滑鼠點選測試的客戶區座標 
  3. UINT flags; // 接收點選測試的結果。有以下幾種:TCHT_NOWHERE(座標點不在標籤上)、TCHT_ONITEM(座標點在標籤上但不在標籤文字或圖示上)、TCHT_ONITEMICON(座標點在標籤圖示上)、TCHT_ONITEMLABEL(座標點在標籤文字上) 
  4. } TCHITTESTINFO, *LPTCHITTESTINFO;  

       4. NMTCKEYDOWN結構體

       該結構體包含了標籤控制元件中鍵盤按下的相關資訊。主要用在TCN_KEYDOWN通知訊息中。

C++程式碼
  1. typedefstruct 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()函式如下:

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。最後還是謝謝各位的關注和支援,歡迎大家留言進行討論學習,謝謝。