Radek Chalupao programování a počítačích, vývoj software, školení ...
Domů | Články | Ukázky kódu | Tipy a triky | Aktuality | Školení a konzultace | Vývoj software | Freeware | Kontakt

Pracujeme s ComboBoxem.  2.2.2002

V tomto článku poznáme trochu blíže ovládací prvek ComboBox, česky překládaný jako rozbalovací seznam. Podobně jako ListBox umožňuje uživateli výběr z existujících položek. Navíc umožňuje také uživateli přímo zapisovat text do editačního pole, pokud má nastaven příslušný styl.

win-api-combobox

Řekneme si nejdříve o 3 typech ComboBoxu:

Simple ComboBox

Simple ComboBox má ve stylu okna hodnotu CBS_SIMPLE, kterou uvedeme při jeho ručním vytváření nebo ve skriptu prostředků. V editoru prostředků pak jednoduše nastavíme vlastnost Type na hodnotu Simple. Tento typ ComboBoxu má oba prvky (Edit i ListBox) trvale zobrazené. Při změně výběru v ListBoxu se text vybraného řádku automaticky zobrazí v editačním poli ComboBoxu. Uživatel může do editačního pole také zapisovat vlastní text. Pozor! V editoru prostředků musíme po nastavení typu na Simple roztáhnout ComboBox do příslušné požadované výšky. V opačném případě by se zobrazoval pouze ve formě jednoho řádku, ve které by sice bylo možné klávesami šipka nahoru nebo dolů listovat, ale nedosáhli bychom výsledku, který jsme pravděpodobně zamýšleli.

Drop down

Tento typ ComboBoxu (ve stylu okna má hodnotu CBS_DROPDOWN) je představován editačním polem (prvek Edit) s rozbalovacím tlačítkem, přičemž rozbalovací část (prvek ListBox) může být rozbalena pouze v době kdy má ComboBox fokus. Jakmile uživatel přeskočí (například klávesou Tab) na jiné okno, ComboBox se automaticky zabalí, aniž by uživatel proti tomu mohl cokoli dělat. Také v tomto typu ComboBoxu je uživateli umožněno zapisovat do editačního pole. Pozor! Častým problémem začátečníků bývá nastavení dostatečné výšky rozbalovacího seznamu. Pokud totiž necháte ComboBox tak, jak jej umístíte na dialog v editoru prostředků bude i při větším počtu položek "rozbalen" pouze jeden řádek vzhledu prvku Edit s malými skrolovacími šipkami, kterými je možné procházet položky ComboBoxu. Správné nastavení provedeme v editoru prostředků kliknutím na rozbalovací šipku, po kterém se nám zobrazí roztahovací obdélník, který pak můžeme tažením za jeho spodní okraj roztáhnout do velikosti, která představuje maximální výšku, do které se rozbalí ComboBox za běhu programu.

Drop List

Tento typ ComboBoxu (styl okna CBS_DROPDOWNLIST) je podobný předchozímu s tím rozdílem, že uživatel nemůže zapisovat vlastní text. Jeho nastavení v editoru prostředků je stejné jako u předchozího typu Drop down.

Naplnění položek ComboBoxu

Položky ComboBoxu můžeme programově přidávat jednou ze dvou zpráv CB_ADDSTRINGa CB_INSERTSTRING. Zpráva CB_ADDSTRING přidá položku na konec a v případě, že má ComboBox nastavenu vlastnost CBS_SORT, je položka automaticky zatříděna podle abecedy. Vlastnost (styl okna) CBS_SORT nastavíme v editoru prostředků jako vlastnost Sort, která má ve Visual C++ výchozí hodnotu true, i když osobně si myslím, že v praxi u většiny ComboBoxů, které jsem použil, jsem toto automatické třídění zrušil. Druhou zprávou pro přidání položky ComboBoxu je CB_INSERTSTRING, jejímž parametrem lParam je text přidávané položky a parametr wParam určuje index, který má nově přidaná položka mít. Na rozdíl od zprávy CB_ADDSTRING namá nastavení stylu CBS_SORT (automatické třídění) žádný vliv a položka je přidána tam, kam řekneme. Pokud chceme touto zprávou přidat položku na konec, uvedeme jako parametr wParam hodnotu -1. Ukázku přidání položek ComboBoxu funkci voláme při zachycení zprávy WM_INITDIALOG vidíte v následujícím výpisu:
void NaInitDialog(HWND hWnd)
{
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_ADDSTRING, 0, (LPARAM)_T("1. řádek"));
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_ADDSTRING, 0, (LPARAM)_T("2. řádek"));
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_ADDSTRING, 0, (LPARAM)_T("3. řádek"));
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_ADDSTRING, 0, (LPARAM)_T("4. řádek"));
  // přidání dalších položek ...
}

Detekce změny výběru, zjištění a nastavení výběru v programu

V následujícím kódu si ukážeme jak detekovat změnu výběru položky ComboBoxu. Budeme zachytávat změnu jednoho z rozbalovacích ComboBoxů, zjistíme index aktuálně vybrané položky a stejnou položku (index) nastavíme jako vybranou ComboBoxu typu Simple. Funkce kterou budeme volat při zjištění změny výběru uživatelem, vypadá takto:
void NaZmenaVyberu(HWND hCombo)
{
  LRESULT vyber = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
  SendDlgItemMessage(GetParent(hCombo), IDC_SIMPLE, CB_SETCURSEL, vyber, 0);
}
Jak a kdy volat tuto zprávu? Při změně výběru dostane vlastník ComboBoxu, tedy naše dialogové okno oznamovací zprávu CBN_SELCHANGE, která přijde prostřednictvím zprávy WM_COMMAND. V následujícím výseku z kódu procedury dialogu je vidět její obsluha:
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch ( uMsg )
  {
    case WM_COMMAND:
      switch ( LOWORD(wParam) )
      {
        case IDC_DROPDOWN:
        case IDC_DROPLIST:
          if ( HIWORD(wParam) == CBN_SELCHANGE)
            NaZmenaVyberu((HWND)lParam);
          break;
        case IDC_SIMPLE:
          ZjistiTextPolozky((HWND)lParam);
          break;
        // další příkazy ...
      }
      break;
    // Další zprávy ...
  }
  return FALSE;
}
Využíváme parametru lParam, který u zprávy WM_COMMAND představuje handle okna ovládacího prvku, kterého se zpráva týká. Jak je vidět z dosavadního výkladu, práce s položkami ComboBoxu je obdobná práci s ListBoxem, který jsme již poznali. Rozdílem je pouze první písmeno v názvech identifikátorů příslušných zpráv. Ukažme si ještě spíše pro připomenutí, jak načíst text aktuálně vybrané položky ComboBoxu. Budeme tentokrát detekovat změnu ComboBoxu typu Simple a vypisovat do prvku Static její text. Při detekci změny výběru budeme vola následující funkci, jejíž volání také vidíte ve výpisu nad sebou:
void ZjistiTextPolozky(HWND hCombo)
{
  LPTSTR lpText;
  LRESULT vyber = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
  LRESULT delkaTextu = SendMessage(hCombo, CB_GETLBTEXTLEN, vyber, 0);
  lpText = (LPTSTR)HeapAlloc(GetProcessHeap(), 0,
    (delkaTextu+1) * sizeof(TCHAR));
  SendMessage(hCombo, CB_GETLBTEXT, vyber, (LPARAM)lpText);
  SetDlgItemText(GetParent(hCombo), IDC_COMBO_TEXT, lpText);
  HeapFree(GetProcessHeap(), 0, lpText);
}
Na závěr si ještě ukážeme jak lze programově rozbalit položky ComboBoxu. Na dialog si přidáme tlačítko a v obsluze jeho stisknutí (to jistě již pravidelný čtenář zná) zavoláme tuto funkci, která rozbalí jeden z ComboBoxů na dialogu a navíc nastaví výběr na 5. položku:
void NaRozbalit(HWND hWnd)
{
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_SHOWDROPDOWN, (WPARAM)TRUE, 0);
  SendDlgItemMessage(hWnd, IDC_DROPDOWN, CB_SETCURSEL, (WPARAM)4, 0);
}
Doprovodný projekt je ke stažení zde: win_api_combobox.zip

Máte připomínku, dotaz nebo komentář k článku a souvisejícími tématy?

Napište a odešlete ji emailem

Copyright © 2019  Radek Chalupa