程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 在VC對話框中加入屬性頁

在VC對話框中加入屬性頁

編輯:關於VC++

當一個基於對話框的程序中有相當多的控件時,你一定會想到使用屬性頁來將這些控件分類放置。本文針對這種方法來討論幾種可能實現的方案。

方案一

本方案的例子請見源代碼打包文件中的Property1部分

在對話框上放置一個Tab Control的控件,再在對話框上放置所需的控件(本例放置了2個按鈕,試圖在每個標簽中顯示一個)。然後利用Class Wizard來為Tab Control控件創建一個控件變量,該變量是CTabCtrl類的,再為其他控件也創建相應的控件類。 在主對話框的初始函數中CProperty1Dlg::OnInitDialog()加入如下代碼:

//本例插入兩個標簽,實際運用中可通過循環插入所需個數的標簽,運行後默認第一個標簽被選中
m_tab.InsertItem( 0, _T("Tab1") );
m_tab.InsertItem( 1, _T("Tab2") );
//將不是第一個標簽的控件隱藏掉,只留下你要的控件
m_button2.ShowWindow( SW_HIDE );

再利用ClassWizard處理Tab Control的 TCN_SELCHANGE 的消息。在消息處理函數中,利用CWnd::ShowWindow來使相應的控件顯示和隱藏。

void CProperty1Dlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
//GetCurSel返回當前被選中的標簽的索引號(以0為基礎算起)
int sel = m_tab.GetCurSel();
switch(sel)
{
case 0:
m_button1.ShowWindow( SW_SHOW );
m_button2.ShowWindow( SW_HIDE );
break;
case 1:
m_button2.ShowWindow( SW_SHOW );
m_button1.ShowWindow( SW_HIDE );
break;
}
*pResult = 0;
}

這樣做以後就可以使界面上的控件在不同的標簽中顯示了,但是這個方案也有很多弊病。

所有的控件仍然在一個對話框內,在使用對話框編輯器進行編輯時,操作很不方便。

為了能分類顯示控件,必須用ClassWizard為每一個控件創建一個控件變量,以便利用各控件變量的CWnd基類的ShowWindow函數來顯示和隱藏。有時為了使用DDX和DDV機制來進行數據交換,還要創建一些存放值的變量,這樣就使得整個對話框類變得相當龐大難以操作。

當然你也可以使用數組來存放那些控件變量或值變量,但是這樣並不是最好,有時一些不相關的控件變量放入一個數組中,通過沒有實際意義的數組索引號來訪問控件,對程序的編寫會造成麻煩。 最好能將所有控件進行分類,放入不通對話框類中,這些對話框作為子對話框出現在主對話框中。可以。現在看看方案二。

方案二

本方案的例子請見源代碼打包文件中的Property2部分

這個方案中,我將使用MFC中現成的CPropertySheet和CPropertyPage類來完成將控件分散到各個對話框類中。

首先加入兩個(或數個)對話框資源。修改各對話框資源的屬性,將對話框的Caption屬性改為你要在標簽上所顯示的文字。將對話框的Style屬性改為:Child, Border屬性改為:Thin, 只選中Title Bar復選框,去掉其他復選框。然後你可以在這些對話框中加入要分開顯示的各個控件。

為上述對話框資源分別制作一個對話框類,該對話框類是從CPropertyPage繼承。這樣一來各子對話框類就好了,主對話框類可以直接使用CPropertySheet類。使用如下代碼即可:

CPropertySheet sheet("屬性頁對話框");
CPage1 page1;
CPage2 page2;
//加入子對話框作為一個屬性頁
sheet.AddPage(&page1);
sheet.AddPage(&page2);
//產生一個模態對話框,也可以使用Create方法來產生一個非模態對話框(具體參見MSDN)
sheet.DoModal();

這樣這個對話框效果如下:

但是會有人問,如何在主對話框中放置其他控件呢?如果直接使用CPropertySheet的話,是不可以的,但是別忘了我們可以從CPropertySheet類繼承自己的類啊!下面來看看方案三的做法。

方案三

本方案的例子請見源代碼打包文件中的Property3部分

首先還是要創建那些要在屬性頁中的顯示的子對話框類,創建步驟和方案二一樣,都是從CPropertyPage繼承。

這次我們將從CPropertySheet類繼承自己的類(假設類名為CMySheet)。我們要在這裡放上一個button控件。那麼現在先在CMySheet中加入一個CButton類的成員變量m_button。

在CMySheet類中的OnInitDialog()函數裡,這樣寫:

BOOL bResult = CPropertySheet::OnInitDialog();
//取得屬性頁的大小
CRect rectWnd;
GetWindowRect(rectWnd);
//調整對話框的寬度
SetWindowPos(NULL, 0, 0,rectWnd.Width() + 100,rectWnd.Height(),SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
CRect rectButton(rectWnd.Width() + 25, 25,rectWnd.Width()+75, 75);
//用程序創建一個按鈕
m_button.Create("Button", BS_PUSHBUTTON, CRect(rectWnd.Width(), 25,rectWnd.Width()+75, 50) , this, 1);
//顯示這個按鈕
m_button.ShowWindow( SW_SHOW );
CenterWindow();
return bResult;

效果如下:

使用方案三雖然能在主對話框中加入控件,但是也比較麻煩,首先所加的控件只能在屬性頁的右邊或下邊。並且用程序來產生控件比較煩瑣,位置與大小不易控制。那麼還有其他方法,既能在對話框中加入屬性頁,又能在主對話框隨意添加控件?還是有的,看看方案四。

方案四

本方案的例子請見源代碼打包文件中的Property4部分

這次我們不從CPropertySheet繼承自己的類,還是直接使用它。各屬性頁的子對話框類還是需要的,創建方法和上述兩個方案相同。

首先我們新建一個基於對話框的工程。在編輯已有的一個主對話框中可以自由加一些所需的控件,但是得留出一定的空間用於放置屬性頁。

在主對話框類裡加入一個CPropertySheet類的一個成員變量(m_sheet)代表整個屬性頁。再加入一些各子對話框類的實例作為成員變量(m_page1、m_page2……)。

在主對話框類的OnInitDialog()函數中加入:

//加入標簽,標簽名由各個子對話框的標題欄決定
m_sheet.AddPage(&m_page1);
m_sheet.AddPage(&m_page2);
//用Create來創建一個屬性頁
m_sheet.Create(this, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT);
RECT rect;
m_sheet.GetWindowRect(&rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
//調整屬性頁的大小和位置
m_sheet.SetWindowPos(NULL, 20, 50, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

效果如下:

這個方案可以自由在主對話框中加一些必要的控件,而且屬性頁中的控件也都分散在了各個子對話框類中,使用非常方便。

但是這樣也有一些缺陷:主對話框不能處理屬性頁上標簽的消息,即點擊標簽時無法通知主對話框。(可能筆者水平有限,理論上應該可以,但筆者尚未解決這個問題)

方案五

本方案的例子請見源代碼打包文件中的Property5部分

這次我們仍然要使用Tab Control,並且從CTabCtrl控件類繼承自己的類(CTabSheet)來處理。(此方法來自CodeGuru的一篇文章,本人稍做修改使其使用更簡便)

首先我先介紹一下如何使用CTabSheet。

先要制作子對話框類,這次的子對話框類不要從CPropertyPage繼承,而是直接從CDialog繼承。並且各個子對話框資源的屬性應設置為:Style為Child, Border為None。

在主對話框資源中,加入一個Tab Control,並且適當調整位置和大小。利用ClassWizard來為這個Tab Control創建一個CTabSheet的控件變量。

在主對話框的OnInitDialog()加入:

m_sheet.AddPage("tab1", &m_page1, IDD_DIALOG1);
m_sheet.AddPage("tab2", &m_page2, IDD_DIALOG2);
m_sheet.Show();

就這樣就可以在對話框上制作出一個完美的屬性頁了。效果和上圖完全一樣。

下面我就來講講CTabSheet類的細節內容。

CTabSheet是從CTabCtrl繼承來的,用於Tab Control的控件類。在類中有一個成員變量用來記錄各子對話框的指針CDialog* m_pPages[MAXPAGE]; MAXPAGE是該類所能加載的標簽的最大值。

類中有一個AddPage方法,用於記錄子對話框的指針和所使用對話框資源的ID號。

BOOL CTabSheet::AddPage(LPCTSTR title, CDialog *pDialog,UINT ID)
{
if( MAXPAGE == m_nNumOfPages )
return FALSE;
//保存目前總的子對話框數
m_nNumOfPages++;
//記錄子對話框的指針、資源ID、要在標簽上顯示的文字
m_pPages[m_nNumOfPages-1] = pDialog;
m_IDD[m_nNumOfPages-1] = ID;
m_Title[m_nNumOfPages-1] = title;
return TRUE;
}

在使用AddPage加入了若干子對話框後,必須調用CTabSheet的Show方法來真正生成標簽和子對話框。

void CTabSheet::Show()
{
//利用CDialog::Create來創建子對話框,並且使用CTabCtrl::InsertItem來加上相應的標簽
for( int i=0; i < m_nNumOfPages; i++ )
{
m_pPages[i]->Create( m_IDD[i], this );
InsertItem( i, m_Title[i] );
}
//由於對話框顯示時默認的是第一個標簽被選中,所以應該讓第一個子對話框顯示,其他子對話框隱藏
m_pPages[0]->ShowWindow(SW_SHOW);
for( i=1; i < m_nNumOfPages; i++)
m_pPages[i]->ShowWindow(SW_HIDE);
SetRect();
}

生成好標簽和子對話框後,調用CTabSheet::SetRect來計算並調整屬性頁的大小。

void CTabSheet::SetRect()
{
CRect tabRect, itemRect;
int nX, nY, nXc, nYc;
//得到Tab Control的大小
GetClientRect(&tabRect);
GetItemRect(0, &itemRect);
//計算出各子對話框的相對於Tab Control的位置和大小
nX=itemRect.left;
nY=itemRect.bottom+1;
nXc=tabRect.right-itemRect.left-2;
nYc=tabRect.bottom-nY-2;
//利用計算出的數據對各子對話框進行調整
m_pPages[0]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW);
for( int nCount=1; nCount < m_nNumOfPages; nCount++ )
m_pPages[nCount]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_HIDEWINDOW);
}

在單擊標簽欄後,應該是相應的子對話框顯示,正在顯示的子對話框應該隱藏。因此利用ClassWizard來處理WM_LBUTTONDOWN消息。

void CTabSheet::OnLButtonDown(UINT nFlags, CPoint point)
{
CTabCtrl::OnLButtonDown(nFlags, point);
//判斷是否單擊了其他標簽
if(m_nCurrentPage != GetCurFocus())
{
//將原先的子對話框隱藏
m_pPages[m_nCurrentPage]->ShowWindow(SW_HIDE);
m_nCurrentPage=GetCurFocus();
//顯示當前標簽所對應的子對話框
m_pPages[m_nCurrentPage]->ShowWindow(SW_SHOW);
}
}

這樣利用CTabSheet這個類就可以輕松地在對話框上放置自己的屬性頁了,並且控件都分散在各子對話框類中,符合對象封裝的思想。而且用這個方法來制作屬性頁就可以利用ClassWizard來輕松地生成消息映射處理Tab Control的消息了。例如:可以處理TCN_SELCHANGE消息來對切換了標簽時進行一些動作。

本文共使用了5種方法在對話框中加屬性頁,當然應該還有其他方法,當本人水平有限,如果各位讀者有更好的方法,可不要忘了告訴我。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved