Pracujeme s ComboBoxem ve WinAPI - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Pracujeme s ComboBoxem ve WinAPI

winapi_logo

15. ledna 2003, 00.00 | V tomto článku poznáme trochu blíže ovládací prvek ComboBox, česky rozbalovací seznam. Naučíme se jak správně nastvit jeho parametry v editoru prostředků a samozřejmě jeho použití v programu.

Pracujeme s ComboBoxem

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.

Terminologická poznámka

Z důvodu jednoznačného rozlišení od termínu zdrojový kód budu od tohoto článku pro zdroje-resources používat český termín "prostředky". V systémových hlášeních české verze Windows XP je již tento termín používán. Když jsem si například nechal s použitím funkce GetLastError vypsat textově význam chyby, která nastala při funkci načítající ikonu nebo bitmapu, v textu bylo (přibližně) uvedeno "...nebyl nalezen prostředek..". Pro, ty které zajímá, jak vypsat význam poslední chyby uvedu následující funkci, která musí být zavolána bezprostředně po zjištění nějaké chyby, například že návratová hodnota funkce CreateWindow nebo LoadBitmap je NULL:

void ZobrazPosledniChybu(HWND hOkno)
{
  LPVOID lpMessage;
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR)&lpMessage, 0, NULL);
  MessageBox(hOkno, (LPCTSTR)lpMessage, g_szAplikace, MB_ICONERROR | 
    MB_SYSTEMMODAL);
  LocalFree(lpMessage);
}

Pozor, funkce GetLastError často ve Windows větve 98 nezjistí nic - o důvod víc proč používat Windows NT/2000 nebo XP.

Ř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_ADDSTRING a 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);
}

Zde si můžete stáhnout doprovodný projekt (Visual C++ .NET) včetně spustitelné release verze: winapi_combobox.zip.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: