1. 程式人生 > >VS2013/MFC程式設計入門之二十四(常用控制元件:組合框控制元件Combo Box)

VS2013/MFC程式設計入門之二十四(常用控制元件:組合框控制元件Combo Box)

 上一節講了列表框控制元件ListBox的使用,本節主要講解組合框控制元件Combo Box。組合框同樣相當常見,例如,在Windows系統的控制面板上設定語言或位置時,有很多選項,用來進行選擇的控制元件就是組合框控制元件。

       組合框控制元件簡介

       組合框其實就是把一個編輯框和一個列表框組合到了一起,分為三種:簡易(Simple)組合框、下拉式(Dropdown)組合框和下拉列表式(Drop List)組合框。下面講講它們的區別。

       簡易組合框中的列表框是一直顯示的,效果如下圖:


       下拉式組合框預設不顯示列表框,只有在點選了編輯框右側的下拉箭頭才會彈出列表框,列表框彈出後如下圖:


       下拉列表式組合框的編輯框是不能編輯的,只能由使用者在下拉列表框中選擇了某項後,在編輯框中顯示其文字。下拉列表式組合框如下圖:


       經過上面的介紹,大家應該知道,最常用的當屬下拉式組合框和下拉列表式組合框了,它們在很多時候能使程式看起來更專業,更簡潔,讓使用者在進行選擇操作時更方便。

       組合框被操作時會向父視窗傳送通知訊息,這些通知訊息及其含義如下:

       CBN_CLOSEUP:組合框的列表框元件被關閉,簡易組合框不會發送該通知訊息
       CBN_DBLCLK:使用者在某列表項上雙擊滑鼠,只有簡易組合框才會傳送該通知訊息
       CBN_DROPDOWN:組合框的列表框元件下拉,簡易式組合框不會發送該通知訊息
       CBN_EDITUPDATE:在編輯框準備顯示改變了的正文時傳送該訊息,下拉列表式組合框不會發送該訊息
       CBN_EDITCHANGE:編輯框的內容被使用者改變了,與CBN_EDITUPDATE不同,該訊息是在編輯框顯示的正文被重新整理後才發出的,下拉列表式組合框不會發送該訊息
       CBN_ERRSPACE:組合框無法申請足夠的記憶體來容納列表項
       CBN_SELENDCANCEL:表明使用者的選擇應該取消,當用戶在列表框中選擇了一項,然後又在組合框控制元件外單擊滑鼠時就會導致該訊息的傳送
       CBN_SELENDOK:使用者選擇了一項,然後按了回車鍵或單擊了下滾箭頭,該訊息表明使用者確認了自己所作的選擇
       CBN_KILLFOCUS:組合框失去了輸入焦點
       CBN_SELCHANGE:使用者通過單擊或移動箭頭鍵改變了列表的選擇
       CBN_SETFOCUS:組合框獲得了輸入焦點

       組合框控制元件的建立

MFC將組合框控制元件的所有操作都封裝到了CComboBox類中。

       我們在對話方塊中加入組合框時,可以往對話方塊模板中拖入Combo Box控制元件,而後新增CComboBox型別的控制元件變數使用,但如果我們想在程式中動態建立的話,就要使用CComboBox類的成員函式Create了。Create函式的原型如下:

virtual BOOL Create(
   DWORD dwStyle,
   const RECT& rect,
   CWnd* pParentWnd,
   UINT nID 
);

       大家可以看出,CComboBox類的Create成員函式同前面幾個控制元件類的Create成員函式非常類似,dwStyle指定組合框控制元件的風格,rect為列表框彈出後組合框的位置和尺寸,pParentWnd是指向父視窗的指標,不能為NULL,nID指定組合框控制元件的ID。最後還是重點講講dwStyle引數。組合框控制元件的風格包括以下幾種,並給出了相應說明:

       CBS_AUTOHSCROLL:使編輯框元件具有水平滾動的風格
       CBS_DISABLENOSCROLL:使列表框在不需要滾動時顯示一個禁止的垂直滾動條
       CBS_DROPDOWN:指定一個下拉式組合框
       CBS_DROPDOWNLIST:指定一個下拉列表式組合框
       CBS_HASSTRINGS:指定一個含有字串的自繪式組合框
       CBS_LOWERCASE:將編輯框和列表框中的所有文字都自動轉換為小寫字元
       CBS_NOINTEGRALHEIGHT:組合框的尺寸由應用程式而不是Windows 指定,通常,由Windows指定尺寸會使列表項的某些部分隱藏起來
       CBS_OEMCONVERT:使編輯框元件中的正文可以在ANSI 字符集和OEM字符集之間相互轉換。這在編輯框中包含檔名時是很有用的
       CBS_OWNERDRAWFIXED:指定自繪式組合框,即由父視窗負責繪製列表框的內容,並且列表項有相同的高度
       CBS_OWNERDRAWVARIABLE:指定自繪式組合框,並且列表項有不同的高度
       CBS_SIIMPLE:指定一個簡易組合框
       CBS_SORT:自動對列表框元件中的項進行排序
       CBS_UPPERCASE:將編輯框和列表框中的所有文字都自動轉換為大寫字元

       dwStyle引數可以是以上風格的組合。跟其他控制元件一樣,建立時一般也還要指定WS_CHILD、WS_VISIBLE、WS_TABSTOP和WS_VSCROLL等風格。

       在對話方塊模板中直接新增組合框控制元件時,其屬性頁中的屬性包含了以上風格,例如屬性Uppercase設為True就相當於指定了CBS_UPPERCASE風格。

       CComboBox類的主要成員函式

因為組合框是由編輯框和列表框組合而成的,所以組合框的操作和編輯框與列表框的操作有很多相似之處,同樣的,CComboBox類的成員函式也和CEdit類與CListBox類的成員函式有很多相似之處,不但功能相似,甚至函式名和引數也很相似。下面大概講解下CComboBox類的主要成員函式,更詳細的內容可以參見MSDN。

       int GetCount( ) const;
       獲取組合框控制元件的列表框中列表項的數量。

       int GetCurSel( ) const;
       獲取組合框控制元件的列表框中選中項的索引,如果沒有選中任何項,該函式返回CB_ERR。

       int SetCurSel(int nSelect);
       在組合框控制元件的列表框中選擇某項。nSelect引數指定了要選擇的列表項的索引,如果為-1則列表框中當前選擇項被取消選中,編輯框也被清空。

       DWORD GetEditSel( ) const;
       獲取組合框控制元件的編輯框中當前選擇範圍的起始和終止字元的位置。該函式返回一個32位數,低16位存放起始位置,高16位存放選擇範圍後第一個非選擇字元的位置。如果該函式用於下拉列表式組合框時,會返回CB_ERR。

       BOOL SetEditSel(int nStartChar,int nEndChar);
       用於在組合框控制元件的編輯框中選擇字元。nStartChar引數指定起始位置,nEndChar引數指定終止位置。

       DWORD_PTR GetItemData(int nIndex) const;
       獲取組合框中指定項所關聯的32位資料。nIndex引數指定組合框控制元件的列表框某項的索引(從0開始)。

       int SetItemData(int nIndex,DWORD_PTR dwItemData);
       為某個指定的組合框列表項設定一個關聯的32位數。nIndex引數指定要進行設定的列表項索引。dwItemData引數指定要關聯的新值。

       void GetLBText(int nIndex,CString& rString) const;
       從組合框控制元件的列表框中獲取某項的字串。nIndex引數指定要獲取字串的列表項的索引,CString引數用於接收取到的字串。

       int GetLBTextLen(int nIndex) const;
       獲取組合框控制元件的列表框中某項的字串長度。nIndex引數指定要獲取字串長度的列表項的索引。  

       int GetTopIndex( ) const;
       獲取組合框控制元件的列表框中第一個可見項的索引。

       int SetTopIndex(int nIndex);
       將組合框控制元件的列表框中某個指定項設定為可見的。nIndex引數指定了該列表項的索引。該函式成功則返回0,有錯誤發生則返回CB_ERR。

       BOOL LimitText(int nMaxChars);
       用於限制使用者在組合框控制元件的編輯框中能夠輸入的最大位元組長度。nMaxChars引數指定了使用者能夠輸入文字的最大位元組長度,如果為0則長度被限制為65535個位元組。

       int AddString(LPCTSTR lpszString);
       為組合框控制元件中的列表框新增新的列表項。lpszString引數是指向要新增的字串的指標。該函式的返回值如果大於等於0,那麼它就是新列表項的索引,而如果有錯誤發生則會返回CB_ERR,如果沒有足夠的記憶體存放新字串則返回CB_ERRSPACE。

       int DeleteString(UINT nIndex);
       刪除組合框中某指定位置的列表項。nIndex引數指定了要刪除的列表項的索引。該函式的返回值如果大於等於0,那麼它就是組合框中剩餘列表項的數量。如果nIndex指定的索引超出了列表項的數量則返回CB_ERR。

       int FindString(int nStartAfter,LPCTSTR lpszString) const;
       在組合框控制元件的列表框中查詢但不選中第一個包含指定字首的列表項。nStartAfter引數指定了第一個要查詢的列表項之前的那個列表項的索引。lpszString指向包含要查詢的字首的字串。該函式的返回值如果大於等於0,那麼它是匹配列表項的索引,如果查詢失敗則返回CB_ERR。

       int InsertString(int nIndex,LPCTSTR lpszString);
       向組合框控制元件的列表框中插入一個列表項。nIndex引數指定了要插入列表項的位置,lpszString引數則指定了要插入的字串。該函式返回字串被插入的位置,如果有錯誤發生則會返回CB_ERR,如果沒有足夠的記憶體存放新字串則返回CB_ERRSPACE。

       int SelectString(int nStartAfter,LPCTSTR lpszString);
       在組合框控制元件的列表框中查詢一個字串,如果查詢到則選中它,並將其顯示到編輯框中。引數同FindString。如果字串被查詢到則返回此列表項的索引,如果查詢失敗則返回CB_ERR,並且當前選擇項不改變。

       此外,CComboBox類還繼承了CWnd類的成員函式GetWindowText、SetWindowText等。

       CComboBox類應用例項     

       最後本文給大家寫一個簡單的例項,說明CComboBox的幾個成員函式及通知訊息等的使用方法。此例項實現的功能:在組合框中包含一個網站列表,切換組合框控制元件的列表框中選擇的列表項時,將新選中的列表項的文字顯示到編輯框中。下面是具體實現步驟:

       1. 建立一個基於對話方塊的MFC工程,名稱設定為“Example24”。

       2. 在自動生成的對話方塊模板IDD_EXAMPLE24_DIALOG中,刪除“TODO: 在此處放置對話方塊控制元件.”靜態文字控制元件、“確定”按鈕和“取消”按鈕。新增一個Combo Box控制元件,ID設定為IDC_WEB_COMBO,Type屬性設為Drop List,為下拉列表式組合框,編輯框不允許使用者輸入,Sort屬性設為False,以取消排序顯示。再新增兩個靜態文字控制元件和一個編輯框,靜態文字控制元件的Caption屬性分別設為“可選擇的大學:”、“您選擇的大學:”,編輯框的ID設為IDC_SEL_WEB_EDIT,Read Only屬性設為True。此時的對話方塊模板如下圖:


       3. 為組合框IDC_WEB_COMBO新增CComboBox型別的控制元件變數m_combobox。

       4. 在對話方塊初始化時,我們將站點名加入到組合框中,並預設選擇第一項,那麼需要修改CExample24Dlg::OnInitDialog()函式為:

BOOL CExample24Dlg::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:  在此新增額外的初始化程式碼
	m_combobox.AddString(_T("上海交通大學"));
	m_combobox.AddString(_T("西安交通大學"));
	m_combobox.AddString(_T("西南交通大學"));
	m_combobox.AddString(_T("北京交通大學"));
	

	return TRUE;  // 除非將焦點設定到控制元件,否則返回 TRUE
}

       5. 我們希望在組合框中選中的列表項改變時,將最新的選擇項實時顯示到編輯框中,那麼這就要用到CBN_SELCHANGE通知訊息。為列表框IDC_WEB_COMBO的通知訊息CBN_SELCHANGE新增訊息處理函式CExample24Dlg::OnCbnSelchangeWebCombo(),並修改如下:

void CExample24Dlg::OnCbnSelchangeWebCombo()
{
	// TODO:  在此新增控制元件通知處理程式程式碼
	CString strbox;
	int nSel;
	// 獲取組合框控制元件的列表框中選中項的索引   
	nSel = m_combobox.GetCurSel();
	// 根據選中項索引獲取該項字串   
	m_combobox.GetLBText(nSel, strbox);
	// 將組合框中選中的字串顯示到IDC_SEL_WEB_EDIT編輯框中   
	SetDlgItemText(IDC_SEL_WEB_EDIT, strbox);
}

       6. 執行程式,彈出結果對話方塊,在對話方塊的組合框中改變選擇項時,編輯框中的顯示會相應改變。效果圖如下:


       組合框的內容就是這些了,大家可以修改組合框的屬性,對比不同屬性時組合框有何不同。相對於CComboBox類數量不少的成員函式來說,本節的例項只是用到了很少的幾個,大家可以根據上面所講試試其他的成員函式。有問題歡迎繼續到本部落格來交流討論。