摘要:很多MFC的程序都用到了屬性表和屬性頁來實現選項設置的界面,但是MFC本身提供的屬性表頁功能有限,界面也很原始,一些新軟件都實現了自己定義的更為美觀的屬性頁。MFC原始的屬性頁是通過CTabCtrl進行切換控制的,本文給出了一種現在較為常見的用CListCtrl進行頁面切換的屬性頁的方法,並且對對列表控件進行了重繪。 CMyPropertySheet是一個從CPropertySheet派生而來的類,因此你仍然可以不費力的利用MFC CPropertySheet的諸多特性,具體使用方法稍後我會詳細說明。
該屬性表的實現效果如下:
圖一
一、使用
CMyPropertySheet的使用方法與MFC的CPropertySheet類似,首先要在程序中創建兩個屬性頁,也就是兩個CPropertyPage的派生對象。然後將MyPropertySheet.cpp 和 MyPropertySheet.h添加至工程,在程序的視圖類頭文件中(假定是個SDI程序)將CMyPropertySheet的頭文件包含進來
#include “MyPropertySheet.h”
在資源視圖裡設置一個新的菜單項“選項”(放在哪兒隨你) 用ClassWizard添加響應函數,在該函數裡添加如下代碼創建一個屬性表對象myPS
CMyPropertySheet myPS;
然後向屬性表添加兩個屬性頁。
myPS.AddPage(&m_page1);
myPS.AddPage(&m_page2);
接下來要添加屬性頁的圖標,該圖標會在對應列表項以及屬性頁的標題上顯示,注意這裡添加的順序要與屬性頁的添加順序保持一致。
myPS.AddIcon(IDI_GLOBAL);
myPS.AddIcon(IDI_ADDITION);
最後創建並顯示該屬性頁。
myPS.DoModal();
剩下的工作就跟一般屬性表完全一樣了。
CMyPropertySheet類提供如下自定義函數,可以對屬性表的外觀進行設置。
SetSepratorColor,SetCaptionColor與SetSelectedColor都接受一個類型為COLORREF的參數,分別用以設置列表分隔線,屬性頁標題以及列表選擇項背景的顏色。
SetListFont設置列表的字體。
讀者也可以根據自己的需要對其進行擴充。
二、實現邏輯
MFC原來的屬性頁是由TabCtrl控制的,而且屬性頁的大小已經與屬性表按比例設置好,因此,要實現如圖一所示的屬性頁,我們有如下幾步工作需要做:
1.對屬性頁原來的TabCtrl進行隱藏。
2.調整屬性表的大小,將屬性頁移至屬性表右側,以容納列表控件。
3.獲得TabCtrl的矩形,根據該矩形畫屬性頁標題。
4.初始化列表控件內容,調整列表項高度。
5.響應列表的NM_CLICK事件,根據得到的點擊項ID進行屬性頁的切換。
其中調整尺寸的工作必須在OnInitDialog函數中進行。
BOOL CMyPropertySheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
//計算屬性頁的矩形,擴大屬性表並將屬性頁其移至右側
CRect rect, rectPage, rectTab;
GetPage(0)->GetWindowRect(&rectPage);
GetWindowRect(&rect);
rect.right += 150;
int nWidth = rectPage.Width();
rectPage.right = rect.right - 20;
rectPage.left = rect.right - nWidth;
ScreenToClient(&rectPage);
m_rectPage = rectPage;
MoveWindow(&rect);
GetPage(0)->MoveWindow(&rectPage);
//隱藏屬性頁原來的TabControl
CTabCtrl *pTab = GetTabControl() ;
pTab->GetWindowRect(&rectTab);
ScreenToClient(&rectTab);
if(!pTab->ShowWindow(SW_HIDE))
return FALSE;
//創建列表控件並用一個CImageList對象與之關聯
if(!m_wndList.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER ,
CRect(10 ,rectTab.top,150,rectPage.bottom ),this,0xFFFF))
return FALSE;
m_wndList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
m_wndList.SetImageList(&m_imgList, LVSIL_SMALL);
InitList();
//設置行高度
CFont font;
font.CreatePointFont(240,_T("宋體"));
m_wndList.SetFont(&font);
CString strCaption;
GetPage(0)->GetWindowText(strCaption);
_tcscpy(m_szCaption, strCaption.GetBuffer(strCaption.GetLength()));
return bResult;
}
屬性頁的切換:
void CMyPropertySheet::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE lpItem = reinterpret_cast(pNMHDR);
m_nSelectedItem = lpItem->iItem ;
if (lpItem->iItem >= 0 && lpItem->iItem < m_wndList.GetItemCount())
{
m_nSelectedItem = lpItem->iItem;
CString strCaption = m_wndList.GetItemText(lpItem->iItem,0);
_tcscpy(m_szCaption, strCaption);
SetActivePage(m_nSelectedItem);
Invalidate();
GetPage(m_nSelectedItem)->MoveWindow(&m_rectPage);
m_wndList.SetFocus();
}
}
三、總結
關於列表控件自繪的問題在這裡不做詳細討論,可以參考源代碼裡面OnNMCustomDraw的部分以及MSDN上的相關資料。對屬性頁的修改還有很多種方法和很多種方式,比如還可以用樹型控件進行控制,這裡提供的方法也可以做一般意義上的推廣 ,並不難實現其它方式的控制。程序在Visual C++ 2005 下編譯通過。
本文配套源碼