4.2.2002
V tomto článku si řekneme o rozšířeném prvku ComboBoxEx, který patří stejně jako ComboBox mezi standardní ovládací prvky Windows. Ovládací prvek ComboBoxEx má některé další rozšiřující vlastnosti a schopnosti oproti běžnému prvku ComboBox. Tato výhoda však současně vyžaduje od programátora "trochu více práce" při jeho vytvoření a použití. Dejme se tedy do práce. Prvním krokem, který musíme učinit před vlastním vytvořením tohoto prvku je správná inicializace knihovny běžných ovládacích prvků, comctl32. Provedeme ji pomocí funkce InitCommonControlsEx s použitím hodnoty ICC_USEREX_CLASSES, jak vidíte v následujícím kódu, umístěném před vlastním vytvořením okna nebo dialogového okna obsahujícího ComboBoxEx.INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(INITCOMMONCONTROLSEX); icc.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES; if ( !InitCommonControlsEx(&icc) ) return -1;Dalším rozdílem je, že prvek ComboBoxEx nemůžeme definovat přímo ve skriptu prostředků, tedy nemůžeme jej vytvořit vizuálním editorem dialogu. Vytvoříme jej tedy v obsluze zprávy WM_INITDIALOG pomocí funkce CreateWindowEx. Tento prvek dále umožňuje jednoduchým způsobem (bez uživatelského kreslení, které samozřejmě není nijak složité, ale..) zobrazovat u položek obrázky. Tyto obrázky musí být obsaženy v prvku ImageList, což je sada jednotlivých obrázků stejné velikosti. Každé položce pak přiřadíme index obrázku z tohoto ImageListu, který má být zobrazován v levé části položky. ImageList nastavíme prvku ComboBoxEx pomocí zprávy CBEM_SETIMAGELIST. Vše uvidíte v dalším výpisu kódu, v kterém si také ukážeme, jak lze nastavit prvku ComboBoxEx vlastní kurzor a dále jiný kurzor editačnímu prvku, obsaženém v ComboBoxu. V té souvislosti si musíme říci, z čeho se vlastně rozšířený ComboBoxEx skládá. Vlastní okno prvku ComboBoxEx totiž v sobě obsahuje ještě (jako dětské okno) běžný prvek ComboBox, a ten jak jsme mohli poznat v minulých dílech obsahuje prvek Edit, představující editační pole v případě, že ComboBox má nastaven potřebný styl CBS_DROPDOWN). Kromě tohoto Editu je pak při rozbalení ComboBoxu dynamicky tvořen prvek ListBox. Položky do prvku ComboBoxEx přidáváme pomocí zprávy CBEM_SETIMAGELIST, jejímž parametrem je adresa struktury COMBOBOXEXITEM, obsahující vlastnosti položky. Nyní se tedy již podívejme na výpis obsluhy zprávy WM_INITDIALOG:
BOOL NaInitDialog(HWND hWnd) { HWND hCombo = CreateWindowEx(0, WC_COMBOBOXEX, NULL, WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN, 0, 0, 0, 100, // polohu a rozměry nastvíme později hWnd, (HMENU)IDC_COMBOEX, // nastavíme ID pro snadnější použití GetModuleHandle(NULL), NULL); g_hImageList = ImageList_LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_IMAGELIST), 16, 3, 0x0000FF00); if ( !g_hImageList ) return FALSE; SendMessage(hCombo, CBEM_SETIMAGELIST, 0, (LPARAM)g_hImageList); SetWindowPos(hCombo, NULL,10,32,250,120,SWP_NOACTIVATE | SWP_NOZORDER); COMBOBOXEXITEM cbei; // Naplníme ComboBox 4 položkami. ZeroMemory(&cbei, sizeof(cbei)); cbei.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; cbei.pszText = _T("první položka"); cbei.iImage = 0; cbei.iItem = 0; cbei.iSelectedImage = 0; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbei); cbei.pszText = _T("druhá položka"); cbei.iImage = 1; cbei.iItem = 1; cbei.iSelectedImage = 1; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbei); cbei.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; cbei.pszText = _T("třetí položka"); cbei.iImage = 2; cbei.iItem = 2; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbei); cbei.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; cbei.pszText = _T("čtvrtá položka"); cbei.iImage = 3; cbei.iItem = 3; cbei.iSelectedImage = 3; SendMessage(hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbei); // Nastavíme výchozí výběr SendMessage(hCombo, CB_SETCURSEL, 1, 0); // Zjistíme "dětský" ComboBox a prvek Edit HWND hChildCombo = (HWND)SendMessage(hCombo, CBEM_GETCOMBOCONTROL, 0,0); HWND hEdit = (HWND)SendMessage(hCombo, CBEM_GETEDITCONTROL, 0,0); // Nastavíme vlastní kurzory SetClassLongPtr(hChildCombo, GCLP_HCURSOR, (LONG_PTR)LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_CURSOR1))); SetClassLongPtr(hEdit, GCLP_HCURSOR, (LONG_PTR)LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_CURSOR2))); return TRUE; }Dále si ještě ukažme, jak v případě rozšířeného ComboBoxu reagovat na změnu výběru položky a následně získat a nějakým způsobem zobrazit některá data položky. Konkrétně budeme zobrazovat text vybrané položky do prvku Static a obrázek vybrané položky ve formě ikony v prvku Static typu STM_ICON - který v editoru dialogu vložíme jako Picture Control. V proceduře dialogu budeme reagovat na oznamovací zprávu CBN_SELCHANGE. Vypíšeme si pro úplnost kompletní kód procedury dialogu z doprovodného příkladu:
// Procedura dialogu INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch ( uMsg ) { case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: EndDialog(hWnd, IDOK); break; case IDCANCEL: EndDialog(hWnd, IDCANCEL); break; case IDC_COMBOEX: if ( HIWORD(wParam) == CBN_SELCHANGE ) NaSelChange(hWnd); break; } break; case WM_INITDIALOG: NaInitDialog(hWnd); NaSelChange(hWnd); break; } return FALSE; }Obsluha oznamovací zprávy CBN_SELCHANGE vypadá pak takto:
void NaSelChange(HWND hWnd) { TCHAR szText[100]; COMBOBOXEXITEM cbei; ZeroMemory(&cbei, sizeof(cbei)); cbei.mask = CBEIF_IMAGE | CBEIF_TEXT; cbei.pszText = szText; cbei.cchTextMax = sizeof(szText); // index vybrané položky cbei.iItem = SendDlgItemMessage(hWnd, IDC_COMBOEX, CB_GETCURSEL, 0, 0); SendDlgItemMessage(hWnd, IDC_COMBOEX, CBEM_GETITEM, 0, (LPARAM)&cbei); SetDlgItemText(hWnd, IDC_COMBO_TEXT, szText); SendDlgItemMessage(hWnd, IDC_IMAGE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)ImageList_GetIcon(g_hImageList, cbei.iImage, ILD_NORMAL)); }Doprovodný projekt je ke stažení zde: win_api_comboboxex.zip
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články