Uživatelsky kreslený ListBox.
29.1.2002
V tomto pokračování ještě zůstaneme u uživatelsky kreslených prvků. Vytvoříme si ListBox, do kterého budeme jako položky přidávat vybrané soubory. V ListBoxu bude pak zobrazena ikona asociovaná s příslušným souborem a jméno souboru vypsané tak, že v případě delšího názvu bude povolen víceřádkový výpis do zbylého prostoru položky ListBoxu, jak vidíte na obrázku: U uživatelsky kresleného ListBoxu (a podobně některých další ovládacích prvků) musíme kromě zprávy WM_DRAWITEM reagovat na zprávu WM_MEASUREITEM, ve které systému řekneme požadované rozměry (v případě ListBoxu výšku) položky. V našem případě budeme zobrazovat velké ikony, takže výšku položky nastavíme a výšku ikony plus řekněme 4 pixely. Tuto zprávu ošetříme přímo v proceduře dialogu, pro obsluhu zprávy WM_DRAWITEM si vytvoříme vlastní funkci, stejně jako pro zobrazení dialogu výběru souboru a přidání vybraného souboru jako položky ListBoxu. Procedura dialogu bude vypadat následovně:// Procedura dialogu
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPMEASUREITEMSTRUCT lpMIS;
switch ( uMsg )
{
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDOK:
EndDialog(hWnd, IDOK);
break;
case IDCANCEL:
EndDialog(hWnd, IDCANCEL);
break;
case IDC_PRIDAT:
PridatSoubor(hWnd);
break;
}
break;
case WM_INITDIALOG:
break;
case WM_DRAWITEM:
DrawItem((LPDRAWITEMSTRUCT)lParam);
break;
case WM_MEASUREITEM:
lpMIS = (LPMEASUREITEMSTRUCT)lParam;
lpMIS->itemHeight = GetSystemMetrics(SM_CYICON) + 4;
break;
}
return FALSE;
}
Funkce pro přidání vybraného souboru jako položky je již pro čtenáře seriálu jednoduchá, pro úplnost ji zde uvedu:
void PridatSoubor(HWND hWnd)
{
TCHAR szSoubor[MAX_PATH];
lstrcpy(szSoubor, _T(""));
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = szSoubor;
ofn.nMaxFile = sizeof(szSoubor);
ofn.lpstrFilter = TEXT("Všechny soubory\0*.*\0");
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if ( !GetOpenFileName(&ofn) )
return;
SendDlgItemMessage(hWnd, IDC_LISTBOX, LB_ADDSTRING, 0,
(LPARAM)szSoubor);
}
Nyní zbývá to nejdůležitější, vykreslit položku ListBoxu při obdržení zprávy WM_DRAWITEM. Identifikátor dané položky dostaneme jako prvek itemID struktury DRAWITELSTRUCT. Z toho je již snadné získat text položky, což je plné jméno souboru. Handle asociované ikony získáme pomocí funkce ExtractAssociatedIcon. Dále zjistíme, zda se jedná o právě vybranou položku otestování přítomnosti hodnoty ODS_SELECTED v prvku itemState. Podle výsledku vyplníme plochu položky jedním z příslušných systémových štětců. Poté vykreslíme ikonu do levé části položky a do zbylého obdélníka vypíšeme název souboru funkcí DrawText, která umožňuje nastavit automatické zalamování řádek v rámci daného obdélníka.
void DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
TCHAR szSoubor[MAX_PATH];
HBRUSH hbPozadi;
SendMessage(lpDIS->hwndItem, LB_GETTEXT, lpDIS->itemID, (LPARAM)szSoubor);
WORD index = 0;
HICON hIcon = ExtractAssociatedIcon(g_hInstance, szSoubor, &index);
if ( lpDIS->itemState & ODS_SELECTED )
{
hbPozadi = GetSysColorBrush(COLOR_HIGHLIGHT);
SetTextColor(lpDIS->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
hbPozadi = GetSysColorBrush(COLOR_WINDOW);
SetTextColor(lpDIS->hDC, GetSysColor(COLOR_WINDOWTEXT));
}
SetBkMode(lpDIS->hDC, TRANSPARENT);
FillRect(lpDIS->hDC, &lpDIS->rcItem, hbPozadi);
DrawIcon(lpDIS->hDC, lpDIS->rcItem.left + 1,
lpDIS->rcItem.top + 2, hIcon);
RECT rect;
CopyMemory(&rect, &lpDIS->rcItem, sizeof(RECT));
rect.left += 34;
DrawText(lpDIS->hDC, szSoubor, -1, &rect,
DT_WORDBREAK | DT_VCENTER);
}
Doprovodný projekt je ke stažení zde: win_api_uk_listbox.zip