VC++深入詳解(6):MFC對話方塊(二)

來源:互聯網
上載者:User

先建立一個MFC工程,然後選擇基於對話方塊的應用程式。我們發現,跟單文檔應用程式相比,它只有3個類:
CAboutDlg:與單文檔的相同,用來顯示協助。這裡其實可以完全不要。

CTestApp:MFC應用程式必不可少的類,它的全域對象theApp代表了應用程式本身

CTestDlg:基於對話方塊的MFC應用程式的主介面,從CDialog派生出來的。
我們先看一個簡單的問題:逃跑按鈕的建立。他其實看起是這樣一件事件:當你把滑鼠移動到某個按鈕上時,這個按鈕卻移動到了另外一個地方,所以你總是點不到它。而它的實現其實是這樣的:我們有兩個按鈕,每當滑鼠移動到第一個按鈕上時,它就把自己隱藏起來,並且調用函數顯示第二個按鈕。按照這種思路,我們展開設計。

首先,在哪裡捕獲滑鼠移動的訊息?肯定不能是CTestDlg類中,否則以移動到對話方塊上,就會顯示或者隱藏按鈕了。我們可以建立一個從CButton派生來的新類CNewButton,使用classWizard來完成;然後將按鈕控制項與這種新類相關聯。在這兩個按鈕上點擊右鍵,使用類嚮導添加CNewButton類的變數m_btn1,m_btn2.我們需要在CTestDlg類的標頭檔中包含:#include "NewButton.h"。下面讓CNewButton捕獲滑鼠移動訊息。為這個類添加WM_MOUSEMOVE的訊息響應函數,在其中調用ShowWindow,參數選擇SW_SHOW來顯示一個視窗,SW_HIDE來隱藏一個視窗。但是,我們要隱藏自己時,也得顯示另外一個視窗,所以我們需要為我們的CTestDlg添加一個成員變數,這個變數中有一個指向CNewButton的指標,裡面儲存的是另一個按鈕的地址。這個初始化工作在OnInitDialog中添加:

m_btn1.m_pBtn = &m_btn2;m_btn2.m_pBtn = &m_btn1;

然後我們的OnMouseMove就簡單了:

void CNewButton::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultShowWindow(SW_HIDE);m_pBtn->ShowWindow(SW_SHOW);CButton::OnMouseMove(nFlags, point);}

為了美觀起見,我們把兩個按鈕中的一個設定為不可見,然後就更像回事了。

下面看如何產生屬性工作表單和嚮導的建立。

下面講何如產生屬性工作表單:
插入->資源->屬性頁面,插入3個屬性頁面,將它們的ID分別設為IDD_PROP1、IDD_PROP2、IDD_PROP3,將它們的標籤設定為Page1,Page2,Page3.
在Page1中放入一個組框:組框的的作用是把相關的內容放在一起,讓使用者使用起來方便,將它的標題改為“請選擇你的職業:”;然後再組框內放置3個按鈕,名字分別設定為:“程式員”、系統工程師、專案經理;然後再組框的旁邊放置一個列表框,然後在他上面放置一個靜態文字框,標題改為:“請選擇你的工作地點”。
在Page2中放置一個組框,名字改為請選擇你的興趣愛好,裡面放4個複選框,名字改為“足球”、“籃球”、“排球”、“遊泳”。
在Page3中放1個組合框,組合框有3種類型:簡易式、下拉式、下拉式清單式。我們這裡選擇下拉式清單。然後在它的上面放一個靜態文框,將名字改為“請選擇你的薪資水平”。
我們有3個資源以後,要為他們產生對應的類使用查看->建立類嚮導->增加新類,名字分別命名為:CProp1,CProp2,CProp3。確保它們的ID與這個三個資源相對應,並將它們的基類設為CPropertyPage。

有了這些類和資源之後,我們才能建立屬性工作表單:首先建立一個CPropSheet對象,然後為它添加前面的3個類的成員變數m_prop1、m_prop2、m_prop3。注意,這裡需要包含它們對應的標頭檔。然後在CPropSheet的建構函式中調用AddPage函數將這3個屬性頁面增加到屬性工作表中。
最後,我們給菜單增加一個功能表項目,並在VIEW類中響應點擊這個功能表項目的訊息。

void CPropView::OnPropertysheet() {// TODO: Add your command handler code hereCPropSheet propSheet("");propSheet.DoModal();}

編譯運行以後,發現上面的漢字是亂碼,在屬性頁面把語言改成中國,把字型改為中文的字型就可以了。
總結一下,整個工作分為下面幾步:
1.建立屬性頁面。
2.將屬性頁面與對應的類相關聯。
3.建立屬性工作表類,為屬性工作表添加與屬性頁面相關的變數,並在建構函式中通過AddPage將屬性頁面添加到屬性工作表中。
4.新增一個功能表項目,在響應這個功能表項目的訊息中,調用屬性工作表的DoModal函數顯示模態屬性工作表。

嚮導的建立
建立嚮導與建立屬性工作表單類似,但是要在DoModal之前,調用CPropSheet的成員SetWizardMode函數。
調用以後,我們發現預設的表單中,第一頁有上一步,最後一頁還有下一步,這都是我們不希望的,我們可以通過SetWizardButtons函數來選擇每一頁上到底有些什麼。通過MSDN,我們可以知道,最好是在 CPropertyPage的OnSetActive函數中調用這個函數。而OnSetActive是一個虛函數,在我們的衍生類別CProp1、CProp2、CProp3中,可以覆蓋它們:

BOOL CProp1::OnSetActive() {// TODO: Add your specialized code here and/or call the base class((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);return CPropertyPage::OnSetActive();}

注意,通過GetParent擷取基類指標以後,應將它們轉化為CPropertySheet*類型。
下面,我們希望如果使用者沒有選擇嚮導中的某一項,就不能進行下一步。
首先我們要將這些選項與某個對象相關聯,來記錄它是否被選中。在單選框上點擊右鍵,選擇建立類嚮導,然後選擇成員變數,我們發現這裡並沒有出現我們單選框的ID號:IDC_RADIO1,這是因為,對於單選框,MFC是增加了一個“group”標記來表示從這個單選框到下一個單選框(不包含)之間的選項只能選一個。我們將第一個單選框的group選項選中,就ok了。我們可以為他關聯一個int型成員變數m_occupation。我們看到,在建構函式中,將它初始化為-1,表示並沒有選擇。當選擇第一個選項時,m_occupation就會被設為0,第二個選項時被設為1,依次類推。
所以,當使用者點擊屬性頁面上的“下一步”按鈕時,應該先要判斷m_occupation。而擷取點擊“下一步”的操作,是通過給CProp1添加虛函數OnWizardNext來實現的。而衍生類別的函數中,還是調用了基類的OnWizardNext函數,這個函數如果返回0,則會自動進入到下一頁,如果返回-1,則會停留在該頁,所以我們可以這樣寫:

LRESULT CProp1::OnWizardNext() {// TODO: Add your specialized code here and/or call the base class//擷取值的時候需要使用這個函數UpdateData();if(-1 == m_occupation){MessageBox("請選擇一個職業!");return -1;}elsereturn CPropertyPage::OnWizardNext();}

下面我們對列表框的內容進行判斷。首先,我們要為列表框增加幾個選項:

BOOL CProp1::OnInitDialog() {CPropertyPage::OnInitDialog();// TODO: Add extra initialization here((CListBox*)GetDlgItem(IDC_LIST1))->AddString("北京");((CListBox*)GetDlgItem(IDC_LIST1))->AddString("天津");((CListBox*)GetDlgItem(IDC_LIST1))->AddString("上海");return TRUE;  // return TRUE unless you set the focus to a control              // EXCEPTION: OCX Property Pages should return FALSE}

與列表框對應的類是CListBox,通過它的AddString函數來增加選項。然後進行判斷,同樣的,我們需要將它和CString類型的成員變數m_workAddr關聯起來:

if("" == m_workAddr){MessageBox("請選擇一個工作地點!");return -1;}

下面處理第二個介面,我們要為這4個複選框按鈕添加4個成員變數m_football、m_basketball、m_volleyball、m_swim,在建構函式中,它們都被初始化為false,所以我們需要判斷它們中的一個是否為TRUE,如果是,就能進行下一步了:

LRESULT CProp2::OnWizardNext() {// TODO: Add your specialized code here and/or call the base classUpdateData();if(m_basketball | m_football | m_volleyball | m_swim){return CPropertyPage::OnWizardNext();}else{MessageBox("請選擇一個愛好!");return -1;}}

下面我們處理第3頁。與第1頁的列表框相似,與組合框相對應的類是CComboBox,通過AddString函數來添加下拉式清單的成員:

BOOL CProp3::OnInitDialog() {CPropertyPage::OnInitDialog();// TODO: Add extra initialization here((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString("1000元以下");((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString("1000元到2000");((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString("2000元到3000");((CComboBox*)GetDlgItem(IDC_COMBO1))->AddString("3000元以上");return TRUE;  // return TRUE unless you set the focus to a control              // EXCEPTION: OCX Property Pages should return FALSE}

運行程式時,我們發現它顯示的順序與我們希望的不同,這是因為MFC內建了排序功能,我們在這個組合框的屬性->樣式中,去掉分類項就可以了。
另外,我們希望這個列表框中有預設的選項,這可以通過SetCurSel來實現。

((CComboBox*)GetDlgItem(IDC_COMBO1))->SetCurSel(0);

因為有了預設選項,我們就不需要判斷使用者是否選擇了。

下面,為我們的選項進行簡單的響應:當點擊完成時,把選擇結果顯示在view類中。首先在Prop3中添加響應點擊完成的虛函數OnWizardFinish,然後為其添加一個CString類型的成員變數m_strSalary用來承載我們選擇的薪資。通過GetCurSel擷取使用者選擇的是哪個選項,通過GetLBText把這個選項的內容儲存到m_strSalary中:

BOOL CProp3::OnWizardFinish() {// TODO: Add your specialized code here and/or call the base classint index;index = ((CComboBox*)GetDlgItem(IDC_COMBO1))->GetCurSel();((CComboBox*)GetDlgItem(IDC_COMBO1))->GetLBText(index,m_strSalary);return CPropertyPage::OnWizardFinish();}

下面正式開始我們的顯示工作。在我們的view類中添加變數來儲存選擇的結果:

int m_iOccupation;CString m_strWorkAddr;BOOL m_bLie[4];CString m_strSalary;

並在建構函式中初始化它們:

CCH_8_PROPView::CCH_8_PROPView(){// TODO: add construction code herem_iOccupation = -1;m_strWorkAddr = "";memset(m_bLike,0,sizeof(m_bLike));m_strSalary = "";}

有了這些資料,如果使用者點擊的是“完成”,那麼我們就該顯示這些資料,如果是“取消”,那麼就不顯示。那麼如何判斷使用者點擊的是什麼呢?是通過DoModal函數的傳回值判斷的:

void CCH_8_PROPView::OnPropertysheet() {// TODO: Add your command handler code hereCPropSheet propSHeet("屬性工作表單");propSHeet.SetWizardMode();if (ID_WIZFINISH  == propSHeet.DoModal()){m_iOccupation = propSHeet.m_prop1.m_occupation;m_strWorkAddr = propSHeet.m_prop1.m_workAddr;m_bLike[0] = propSHeet.m_prop2.m_football;m_bLike[0] = propSHeet.m_prop2.m_basketball;m_bLike[0] = propSHeet.m_prop2.m_volleyball;m_bLike[0] = propSHeet.m_prop2.m_swim;m_strSalary = propSHeet.m_prop3.m_strSalary;Invalidate();}}

我們將嚮導中的選項全部存在view類裡的變數裡,然後調用Invalidate();是得客戶區變為無效,引起重繪。
下來,我們就能夠在OnDraw函數中顯示這些資訊了:

void CCH_8_PROPView::OnDraw(CDC* pDC){CCH_8_PROPDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCString strtmp;strtmp = "你的職業:";switch(m_iOccupation){case 0:strtmp += "程式員";break;case 1:strtmp += "系統工程師";break;case 2:strtmp += "專案經理";break;default:break;}pDC->TextOut(0,0,strtmp);strtmp = "你的工作地點:";strtmp += m_strWorkAddr;TEXTMETRIC tm;pDC->GetTextMetrics (&tm);pDC->TextOut(0,tm.tmHeight, strtmp);strtmp = "你的興趣愛好:";if(m_bLike[0])strtmp += "足球";if(m_bLike[1])strtmp += "籃球";if(m_bLike[2])strtmp += "排球";if(m_bLike[3])strtmp += "遊泳";pDC->TextOut(0,tm.tmHeight*2, strtmp);strtmp = "你的薪資水平:";strtmp += m_strSalary;pDC->TextOut(0,tm.tmHeight*3, strtmp);}

其中,為了能夠在下一行顯示,而不會重複顯示,我們擷取的系統的字型,利用了它的高度資訊。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.