一、控件的介紹
MFC中封裝了許多有用的類,CTabCtrl和CPropertySheet是其中兩個比較常用的類型。CTabCtrl即Tab控件對應的類,Windows應用程序中大量使用了Tab控件。屬性頁對應的是CPropertySheet,你在桌面上右鍵鼠標彈出的顯示對話框就是一個CPropertySheet類型的對象。事實上這類彈出的、類似“屬性頁”的窗口大部分都是CPropertySheet。
其實,這兩個類之間也有着很密切的聯繫。使用Spy++觀察一個屬性頁窗口可以發現,它也包含了一個Tab控件
二、屬性頁的使用
屬性頁的使用比較簡單,過程也很清晰。先說一下,CPropertySheet和CDialog對話框類同樣都派生於CWnd類,所以他倆在使用上有很多相似的地方。我不知道是不是這哥倆太相似了,以至於Spy++把我自建的一個CPropertySheet窗口認作是CDialog。
既然屬性頁和對話框相似,我們只要有了一個屬性頁的類,就可以使用DoModal()方法來產生一個模態的窗口,或者用Create()產生一個非模態的窗口。注意如果顯示非模式的窗口,要考慮變量生存期的問題,這點和非模態對話框是一樣的。
屬性頁窗口裏面那麼多的選項卡是怎麼弄出來的?這就需要CPropertyPage。這是一個對話框類的子類,對應着一個選項卡。對一個屬性頁,我們使用AddPage()方法來添加選項卡
選項卡既然是對話框,我們就可以在資源窗口中建立對話框,然後利用類嚮導爲他建立類,注意要選擇派生自CPropertyPage。MSDN上面說,建立這類對話框資源模板時有幾點要注意
1.保留TitleBar屬性。對話框標題就是將來顯示在選項卡上的標籤
2.對話框風格設爲Child,邊框設爲Thin
3.將對話框設爲Disabled
好了,總結一下屬性頁的使用步驟就是
1.建立模板資源,構造你需要的每一個CPropertyPage。
2.使用CPropertySheet類,用AddPage()方法爲其添加至少一個選項卡。或者,你可以派生一個自己的CMyPropertySheet類,在內部添加上各個CPropertyPage作爲成員變量,並在構造函數中用AddPage
3.在需要使用屬性頁的地方聲明變量,使用DoModal()或者Create()方法顯示屬性頁
三、Tab控件的使用
Tab控件一般用在對話框中。在我看來Tab控件本身並不複雜,其實也就是一組簡單的按鈕而已,因爲它並不能直接對各個選項卡進行操縱。我們需要對用戶選擇選項卡的行爲進行手工地響應
比如你希望對每一個選項卡顯示不同的內容,你必須通過顯示/隱藏不需要的內容。當每一個選項卡上的內容較多時,可以把這些內容放在一個容器裏,比如一個對話框。這樣,一個選項卡對應一個對話框,關係比較清晰。這些對話框應設置爲沒有標題欄、Child風格、無邊框的、非模式的。以此爲例,對話框中使用Tab控件的步驟是
1.在對話框中添加Tab控件
2.爲各選項卡建立對話框模板資源
3.響應Tab控件的TCN_SELCHANGE消息,在OnSelChange()函數中,用ShowWindow()函數顯示欲顯示的選項卡,隱藏其他。非模式對話框的生存期問題這裏仍然存在,不可忽視
4.初始化Tab控件。可在對話框初始化時手工調用OnSelChange()函數的方法來實現.
下面使用使用CTabCtrl或CPropertySheet實現標籤頁:
CTabCtrl
1.先建立一個MFC應用程序,然後在資源管理器中新建一對話框,併爲它建立對應的類,然後從工具箱裏面把Tab Control控件放入該對話框中。
再在對話框類中,聲明一個CTabCtrl變量:
CTabCtrl m_tab;
變量m_tab用來與對話框中的Tab Control控件交互,爲此要在DoDataExchange函數中加入DDX_Control語句:
DDX_Control(pDX, IDC_TAB_NEW, m_tab);
IDC_TAB_NEW是Tab Control控件的ID。
2.建立兩個新對話框,用來當做Tab Control控件的兩個頁。別忘了把Style改爲Child,Border改爲None。然後就可以在上面加其他控件了。
接着分別爲這兩個對話框建立兩個類,比如CPage1和CPage2。
然後在對話框類頭文件中,加入這兩個對話框對象。同時增加一個變量int m_CurSelTab,用了表明是哪個Page即將被切換。
int m_CurSelTab;
CPage1 m_page1;
CPage2 m_page2;
CDialog* pDialog[2]; //用來保存對話框對象指針
在對話框類的初始化函數中需要把CPage1、CPage2和Tab Control關聯起來,並保存頁面地址,設置初始頁面。
//爲Tab Control增加兩個頁面
m_tab.InsertItem(0, _T("Farm"));
m_tab.InsertItem(1, _T("Note"));
//創建兩個對話框
m_page1.Create(IDD_DIALOG1, &m_tab);
m_page2.Create(IDD_DIALOG2, &m_tab);
//設定在Tab內顯示的範圍
CRect rc;
m_tab.GetClientRect(rc);
rc.top += 20;
m_page1.MoveWindow(&rc);
m_page2.MoveWindow(&rc);
//把對話框對象指針保存起來
pDialog[0] = &m_page1;
pDialog[1] = &m_page2;
//顯示初始頁面
pDialog[0]->ShowWindow(SW_SHOW);
pDialog[1]->ShowWindow(SW_HIDE);
//保存當前選擇
m_CurSelTab = 0;
這裏我們用了一個CDialog指針數組來進行保存Tab Control的每個頁,數組的大小是Tab Control頁面的個數,數組下標對應着每個頁面的索引(這樣方便快速存取)。接下來,爲Tab Control添加消息處理程序:
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_NEW, &CTabDlg::OnTcnSelchangeTabNew)
void CTabDlg::OnTcnSelchangeTabNew(NMHDR *pNMHDR, LRESULT *pResult)
{
//把當前的頁面隱藏起來
pDialog[m_CurSelTab]->ShowWindow(SW_HIDE);
//得到新的頁面索引
m_CurSelTab = m_tab.GetCurSel();
//把新的頁面顯示出來
pDialog[m_CurSelTab]->ShowWindow(SW_SHOW);
*pResult = 0;
}
3.如果要在Tab Control控件外面獲取其內部對話框中控件的數據,就需要使用DDX/DDV機制,還要調用相應的UpdateData函數。
m_page1.UpdateData();
m_page2.UpdateData();
CPropertySheet
1.先建立MFC應用程序,然後在資源管理器中新建一對話框,併爲它建立對應的類,在編輯該對話框,可以自由加一些所需的控件,但得留出一定的空間用於放至
標籤頁。在主對話框類里加入一個CPropertySheet類的一個成員變量m_sheet代表整個標籤頁。
2.接着分別爲創建兩個對話框,建立兩個與之對應的類時,注意選擇基類爲CPropertyPage。假設新生成兩個類爲CPage1,CPage2。
3.在剛纔加入m_sheet成員的位置,加入上述類型成員變量m_page1,m_page2。
CPropertySheet m_sheet;
CPage1 m_page1;
Cpage2 m_page2;
在主對話框類的OnInitDialog()函數中加入:
//加入標籤,標籤名由各個子對話框的標題欄決定
m_sheet.AddPage(&m_page1);
m_sheet.AddPage(&m_page2);
//對修改標籤頁title
m_page1.m_psp.dwFlags|=PSP_USETITLE;
m_page1.m_psp.pszTitle= "標籤頁A";
m_page2.m_psp.dwFlags|=PSP_USETITLE;
m_page2.m_psp.pszTitle= "標籤頁B";
//用Create來創建一個屬性頁
m_sheet.Create(this, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT);
//調整m_sheet位置
RECT rect;
GetWindowRect(&rect);
m_sheet.MoveWindow(&rect);