Win32的標准控件之中,列表控件(ListBox)並沒有和列表視圖(ListView)一樣提供水平滾動條,所以如果列表項的長度超過列表的寬度的話,那麼超出的部分將無法顯示。在本文中我將以一個簡單的例子來說明如何使用SDK來解決這一問題,在這個例子中,我將為一個列表控件添加100行如下格式的文本:
This is a very very very very very long sentence - line 1
This is a very very very very very long sentence - line 2
……
這段添加文本的代碼為:
case WM_INITDIALOG:
{
int i;
TCHAR str[100];
for(i = 0; i < 100; i++)
{
wsprintf(str, "This is a very very very very very long sentence - line %d", i + 1);
SendDlgItemMessage(hDlg, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)str);
}
}
break;
當然,在添加水平滾動條之前,就是下圖這樣的效果:
下面我來為這個列表控件來添加水平滾動條,首先需要在資源的設計中為這個列表控件設置水平滾動條,然後就可以通過向列表控件發送一條LB_SETHORIZONTALEXTENT消息來向它添加水平滾動條了。在這條消息的附加參數中,wParam參數就是以像素為單位的水平滾動條長度,lParam不使用。那麼,可以為這個滾動條設置一個足夠的長度(假設為500),有以下的代碼:
case WM_INITDIALOG:
{
HDC hdc;
int i;
TCHAR str[100];
for(i = 0; i < 100; i++)
{
wsprintf(str, "This is a very very very very very long sentence - line %d", i + 1);
SendDlgItemMessage(hDlg, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)str);
}
SendDlgItemMessage(hDlg, IDC_LIST, LB_SETHORIZONTALEXTENT, 500, 0); // 設置長度為500像素的水平滾動條
}
break;
這段代碼執行完畢後,效果如下圖:
如你所見,我們已經成功地為列表控件添加了水平滾動條。然而美中不足的是,500這一長度似乎太長,很不美觀。那麼我們所需要的,就是一種方法,我們能通過這種方法來將字符串的長度換算成為一個適當的像素長度,這樣就可以使這個界面較為美觀了。幸運的是,Win32 API之中的確有這麼一個函數:
BOOL GetTextExtentPoint32(
HDC hdc, // 相關設備句柄
LPCTSTR lpString, // 字符串
int cbString, // 字符串的字符數(即長度)
LPSIZE lpSize // 用來接收字符串的尺寸
);
也許你會很納悶:這個函數為什麼要和HDC扯上關系?其實原因很簡單:Windows是一個基於圖形的操作系統,所以所有的文本也是被Windows系統“畫”到界面上去的。那麼這樣一來,字符串的長度自然和所選用的字體和字體的大小發生關系,字符串的像素寬度也必須這麼計算了。我的代碼如下:
case WM_INITDIALOG:
{
HDC hdc;
SIZE s;
int i;
TCHAR str[100];
hdc = GetDC(hDlg); // 獲得相關設備句柄
for(i = 0; i < 100; i++)
{
wsprintf(str, "This is a very very very very very long sentence - line %d", i + 1);
GetTextExtentPoint32(hdc, str, lstrlen(str), &s); // 獲取字符串的像素大小
// 如果新的字符串寬度大於先前的水平滾動條寬度,則重新設置滾動條寬度
if (s.cx > (LONG)SendDlgItemMessage(hDlg, IDC_LIST, LB_GETHORIZONTALEXTENT, 0, 0))
SendDlgItemMessage(hDlg, IDC_LIST, LB_SETHORIZONTALEXTENT, (WPARAM)s.cx, 0);
SendDlgItemMessage(hDlg, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)str);
}
ReleaseDC(hDlg, hdc);
}
break;
現在終於可以輕松的呼出一口氣了,看看效果吧:
你可能還會問,為什麼右邊的部分還有一點空白?對於這個問題,GetTextExtentPoint32的備注是這麼解釋的:“由於有的設備緊縮字符,因此一個字符串裡字符的范圍之和或許不等於字符串的范圍,計算的字符寬度考慮了由SetTextCharacterExtra設備的字符間隔。”
在本文結束的時候,我突然在MSDN中的列表控件消息裡發現了LB_GETTEXTLEN這個消息,它可以用來獲得列表項的字符長度。這樣看來,獲得列表項的像素長度也許也能夠通過字符長度來換算,不過我沒有找到這種方法。