前面兩節講了比較常用的按鈕控件,並通過按鈕控件實例說明了具體用法。本文要講的是列表框控件(ListBox)及其使用實例。
列表框控件簡介
列表框給出了一個選項清單,允許用戶從中進行單項或多項選擇,被選中的項會高亮顯示。列表框可分為單選列表框和多選列表框,顧名思義,單選列表框中一次只能選擇一個列表項,而多選列表框可以同時選擇多個列表項。
列表框也會向父窗口發送通知消息。這些通知消息含義如下:
LBN_DBLCLK:用戶用鼠標雙擊了一列表項,只有具有LBS_NOTIFY的列表才能發送該消息。
LBN_ERRSPACE:列表框不能申請足夠的動態內存來滿足需要。
LBN_KILLFOCUS:列表框失去焦點。
LBN_SELCANCEL:當前的選擇被取消,只有具有LBS_NOTIFY的列表框才能發送該消息。
LBN_SETFOCUS:列表框獲得輸入焦點。
WM_CHARTOITEM:當列表框收到WM_CHAR消息后,向父窗口發送該消息,只有具有LBS_WANTKEYBOARDINPUT風格的列表框才會發送該消息。
WM_VKEYTOITEM:當列表框收到WM_KEYDOWN消息后,向父窗口發送該消息,只有具有LBS_WANTKEYBOARDINPUT風格的列表框才會發送該消息。
列表框控件的創建
MFC將列表框控件的所有操作都封裝到了CListBox類中。
創建列表框控件時,可以在對話框模板中直接拖入列表框控件ListBox,然后添加控件變量使用。但如果需要動態創建列表框,就要用到CListBox類的Create成員函數了。Create成員函數的原型如下:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
參數rect指定了列表框控件的位置和尺寸,pParentWnd為父窗口的指針,nID用於指定列表框控件的ID。最后終點講講參數dwStyle,它指定了列表框的風格,以下是各種風格的說明:
LBS_EXTENDEDSEL:支持多重選擇,在點擊列表框項時按住Shift鍵或Ctrl鍵即可選擇多個項。
LBS_MULTICOLUMN:指定一個水平滾動的多列列表框,通過調用CListBox::SetColumnWidth來設置每列的寬度。
LBS_MULTIPLESEL:支持多重選擇。列表項的選擇狀態隨着用戶對該項單機或雙擊鼠標而翻轉。
LBS_NOINTEGRALHEIGHT:列表框的尺寸由應用程序而不是Windows指定。通常,Windows指定尺寸會使列表項的某些部分隱藏起來。
LBS_NOREDRAW:當選擇發生變化時防止列表框被更新,可發送消息改變改變該風格。
LBS_NOTIFY:當用戶單擊或雙擊鼠標時通知父窗口。
LBS_OWNERDRAWFIXED:指定自繪式列表框,即由父窗口負責繪制列表框的內容,並且列表項具有相同的高度。
LBS_SORT:使插入列表框中的項按升序排列。
LBS_STANDARD:相當於指定了WS_BORDER|WS_VSCROLL|LBS_SORT。
LBS_USETABSTOPS:使列表框在顯示列表項時識別並擴展制表符('\t'),默認的制表寬度是32個對話框單位。
LBS_WANTKEYBOARDINPUT:允許列表框的父窗口接收WM_VKEYTOITEM和WM_CHARTOITEM消息,以響應鍵盤輸入。
LBS_DISABLEENOSCROLL:使列表框在不需要滾動時顯示一個禁止的垂直滾動條。
dwStyle可以是以上所列風格的組合。與其他控件一樣,除了這些風格一般還要為列表框控件設置WS_CHILD、WS_VISIBLE、WS_TABSTOP、WS_BORDER、WS_VSCROLL等風格。一般創建單選列表框時,風格要設置為:WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_STANDARD,如果不希望列表框排序顯示則應去掉LBS_STANDARD。創建多選列表框時,只需要在單選列表框風風格后添加LBS_MULTIPLESEL或LBS_EXTENDEDSEL風格。
對於對話框模板中直接添加的列表框控件,其屬性頁中的屬性也包含了以上風格,例如屬性Multicolumn對應的就是LBS_MULTICOLUMN風格。
CListBox類的主要成員函數
int GetCount() const;
返回值:返回列表框中列表項的數目,如果發生錯誤則返回LB_ERR。
int GetSel(int nIndex) const;
參數:nIndex指定某個列表項的索引。
返回值:返回nIndex制定的列表項的狀態。如果此列表項倍選擇了則返回一個正值,否則返回0,若發生錯誤則返回LB_ERR。
int SetSel(int nIndex, BOOL bSelect = TRUE);
此函數用於多選列表框,使用它可以選擇或取消選擇指定的列表項。
參數:nIndex指定某個列表項的索引,若為-1則相當於指定了所有列表項。bSelect為TRUE時選擇制定列表項,否則取消選擇列表項。
返回值:如果發生錯誤則返回LB_ERR。
int AddString(LPCTSTR lpszItem);
此函數用來向列表框中添加字符串。如果列表框指定了LBS_SORT風格,字符串就被以排序順序插入到列表框中,如果沒有指定LBS_SORT風格,字符串就被添加到列表框的結尾。
參數:lpszItem指定了要添加的字符串。
返回值:返回字符串在列表框中添加的位置。如果發生錯誤則返回LB_ERR,內存不夠則返回LB_ERRSPACE。
int InsertString(int nIndex, LPCTSTR lpszItem);
該函數用來在列表框中的指定位置插入字符串。與AddString函數不同的是,InsertString函數不會導致LBS_SORT風格列表框重新排序。不要在具有LBS_SORT風格的列表框中使用InsertString函數,以免破壞列表項的次序。
參數:參數nIndex給出了插入位置(索引),如果值為-1,則字符串將被添加到列表的末尾。參數lpszItem指定了要插入的字符串。
返回值:返回實際的插入位置,若發生錯誤,會返回LB_ERR或LB_ERRSPACE。
int DeleteString(UINT nIndex);
該函數用於刪除指定的列表項。
參數:nIndex指定了要刪除項的索引。
返回值:函數的返回值為剩下的列表項數目,如果nIndex超過了實際的列表項總數,則返回LB_ERR。
void ResetContent();
該函數用於清除所有列表項。
int GetText(int nIndex, LPCTSTR lpszBuffer) const;
void GetText(int nIndex, CString& rString) const;
這兩個成員函數用於獲取指定列表項的字符串。參數nIndex指定了列表項的索引。參數lpszBuffer指向一個接收字符串的緩沖區。引用參數rString則指定了接收字符串的CString對象。第一個版本的函數會返回獲得的字符串的長度,若出錯,則返回LB_ERR;第二個版本的函數則不會。
int GetTextLen(int nIndex) const;
該函數返回指定列表項的字符串的字節長度。
參數:nIndex指定了列表項的索引。
返回值:若出錯則返回LB_ERR。
int GetCurSel() const;
該函數僅適用於單選列表框,用來返回當前被選擇項的索引,如果沒有列表項被選擇或有錯誤發生,則函數返回LB_ERR。
int SetCurSel(int nSelect);
該函數僅適用於單選列表框,用來選擇指定的列表項。該函數會滾動列表框以使選擇項可見。參數nIndex指定了列表項的索引,若為-1,那么將清除列表框中的選擇。若出錯函數返回LB_ERR。
int GetSelCount() const;
該函數僅用於多重選擇列表框,它返回選擇項的數目,若出錯函數返回LB_ERR。
int FindString(int nStartAfter, LPCTSTR lpszItem) const;
該函數用於對列表項進行與大小無關的搜索。參數nStartAfter指定了開始搜索的位置,合理指定nStartAfter可以加快搜索速度,若nStartAfter為-1,則從頭開始搜索整個列表。參數lpszItem指定了要搜索的字符串。函數返回與lpszItem指定的字符串相匹配的列表項的索引,若沒有找到匹配項或發生錯誤,則會返回LB_ERR。FindString函數想從nStartAfter指定的位置開始搜索,若沒有找到匹配項,則會從頭開始搜索列表。只有找到匹配項,或對整個列表搜索完一遍后,搜索過程才會停止,所以不必擔心會漏掉要搜索的列表項。
int SelectString(int nStartAfter, LPCTSTR lpszItem);
該函數僅適用於單選列表框,用來選擇與指定字符串相匹配的列表項。該函數會滾動列表框以使選擇項可見。參數的意義及搜索的方法與函數FindString類似。如果找到了匹配的項,函數返回該項的索引,如果沒有匹配的項,函數返回LB_ERR並且當前的選擇不被改變。
CListBox類應用實例
最后給大家寫一個簡單的實例,說明CListBox的幾個成員函數及通知消息等的使用方法。此實例實現的功能:在單選列表框中顯示一個網站列表,然后再用鼠標左鍵選擇某列表項時,將選中列表項的文本顯示到編輯框中。下面是具體實現步驟:
1、創建一個基於對話框的MFC工程,名稱設置為”MFCListBoxDemo“。
2、在自動生成的對話框模板IDD_MFCLISTBOXDEMO_DIALOG中,刪除"TODO:Place dialog controls here."靜態文本框、“確定”按鈕和“取消”按鈕。添加一個ListBox控件,ID設置為IDC_WEB_LIST,Sort屬性設為False,以取消排序顯示。再添加一個靜態文本控件和一個編輯框,靜態文本控件的Caption屬性設為“您選擇的站點:”,編輯框的ID設為IDC_SEL_WEB_EDIT,Read Only屬性設為True。此時的對話框模板如下圖:

3、為列表框IDC_WEB_LIST添加CListBox類型的控件變量m_listBox。
4、在對話框初始化時,我們將站點名加入到列表框,那么需要修改CMFCListBoxDemoDlg::OnInitDialog()函數為:
C++代碼:
BOOL CMFCListBoxDemoDlg::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_listBox.AddString(_T("新浪")); // 在列表框末尾添加字符串“新浪”
m_listBox.AddString(_T("博客園")); // 在列表框末尾添加字符串“博客園”
m_listBox.AddString(_T("貓撲")); // 在列表框結尾處添加字符串“貓撲”
m_listBox.AddString(_T("網易")); // 在列表框結尾處添加字符串“網易”
m_listBox.InsertString(2, _T("百度")); // 在列表框中索引為2的位置插入字符串“百度”
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
5、我們希望在選中列表項改變時,將最新的選擇項實時顯示到編輯框中,那么這就要用到LBN_SELCHANGE通知消息。為列表框IDC_WEB_LIST的通知消息LBN_SELCHANGE添加消息處理函數CMFCListBoxDemoDlg::OnLbnSelchangeWebList(),並修改如下:
C++代碼:
void CMFCListBoxDemoDlg::OnLbnSelchangeWebList()
{
// TODO: 在此添加控件通知處理程序代碼
CString strText;
int nCurSel;
nCurSel = m_listBox.GetCurSel(); // 獲取當前選中列表項
m_listBox.GetText(nCurSel, strText); // 獲取選中列表項的字符串
SetDlgItemText(IDC_SEL_WEB_EDIT, strText); //將選中列表項的字符串顯示到編輯框中
}
6、運行程序,彈出結果對話框,在對話框的列表中用鼠標改變選中項時,編輯框的顯示會相應改變。效果圖如下:

關於列表框ListBox的講解就到此為止了。如果大家想試驗更多的列表框成員函數,可以在上面的小例子中加入更多的更能來體會。
