Radek ChalupaČlánkyUkázky kóduVývoj softwareKontakt

Pracujeme s ComboBoxem - II.  3.2.2002

V tomto článku zůstaneme ještě u ovládacího prvku ComboBox. Ukážeme si některé další techniky jeho použití a ovládání.

win-api-combobox-2

Nastavení šířky rozbalovacího seznamu

Pokud je předpoklad, že ComboBox obsahuje nebo může obsahovat položky, jejichž šíře textu je větší než šířka vlastního ComboBoxu (v nerozbaleném stavu), je žádoucí přiměřeným způsobem nastavit (zvětšit) šířku rozbalovacího seznamu. Provedeme to pomocí zprávy CB_SETDROPPEDWIDTH, jak je vidět v následujícím příkladu, který nastaví tuto šířku na 350 pixelů:
SendDlgItemMessage(hWnd, IDC_COMBO, CB_SETDROPPEDWIDTH, 350, 0);

Jak urychlit naplnění větším množstvím položek

Pokud naplňujeme programově ComboBox najednou velkým množstvím položek, většinou v nějakém cyklu, můžeme urychlit tento proces použitím zprávy WM_SETREDRAW. Touto zprávou totiž můžeme zakázat a nebo opět povolit překreslení prvku (nejen ComboBoxu) při změně jeho obsahu, čímž je přidání jedné položky. Nejprve tedy překreslování zakážeme, provedeme celý cyklus přidání položek a poté překreslení opět povolíme, takže překreslen je až konečný stav po naplnění. Následující kód ukazuje přidání necelých 10000 položek tak, že v položce je vypsáno číslo řádku a hodnota vrácená funkcí GetTickCount, což je počet milisekund od startu systému (samozřejmě její "citlivost" není 1 ms, ale přibývá po určitých skocích -ale to je už jiné téma).
  TCHAR szText[100];
  // Zakážeme překreslování
  SendDlgItemMessage(hWnd, IDC_COMBO, WM_SETREDRAW, FALSE, 0);
  for ( int i = 4; i < 10000; i++ )
  {
    _stprintf(szText, _T("řádek %d. přidán ve %d ms"), i, (int)GetTickCount());
    SendDlgItemMessage(hWnd, IDC_COMBO, CB_ADDSTRING, 0, (LPARAM)szText);
  }
  SendDlgItemMessage(hWnd, IDC_COMBO, CB_SETCURSEL, 2, 0);
  // Povolíme překreslení
  SendDlgItemMessage(hWnd, IDC_COMBO, WM_SETREDRAW, TRUE, 0);
Poznámka pro přemýšlivé: v doprovodném projektu je tento kód pro zjednodušení umístěn v obsluze zprávy WM_INITDIALOG, která přijde ještě před vlastním zobrazením celého dialogu, takže lze předpokládat, že zde je použití této techniky zbytečné. Je zde pouze z demonstračních důvodů.

Zajištění viditelnosti určité položky při programovém rozbalení

V některých případech můžeme chtít, aby po programovém rozbalení ComboBoxu bylo zajištěno, že určitá položka bude ve viditelné části rozbalovacího seznamu bez nutnosti k ní odskrolovat. Toto zajistíme pomocí zprávy CB_SETTOPINDEX, jejímž parametrem wParam je právě index položky, která má být viditelná. Postup vidíte v následující funkci, volané na stisk tlačítka.
void NaRozbalit(HWND hWnd)
{
  SendDlgItemMessage(hWnd, IDC_COMBO, CB_SHOWDROPDOWN, TRUE, 0);
  SendDlgItemMessage(hWnd, IDC_COMBO, CB_SETTOPINDEX,  (WPARAM)200, 0);
}
Výsledek vidíte na úvodním obrázku. Možná vám připadá nějaké divné písmo, kterým jsou vypsány položky v rozbalené části ComboBoxu. Proč je tomu tak, si řekneme nyní.

Jednoduché zjištění dalších informací o ComboBoxu ve Windows XP

Technika, použitá v tomto odstavci je omezena na použití v operačním systému Windows XP. Pro přeložení a vytvoření aplikace není samozřejmě nutné mít Windows XP. Ty jsou nutné pouze pro její spuštění. Naopak pro překlad i ve Windows XP musíte mít dostatečně aktuální verzi Windows SDK (Software Development Kit). Tento "balík" obsahuje (kromě jiného) nutné knihovny a hlavičkové soubory, potřebné pro překlad a sestavení aplikace. Pokud máte Visual C++ .NET, máte již tyto soubory dostatečně aktuální. V případě starší verze Visual C++ lze poslední verzi (v okamžiku kdy píšu tyto řádky je poslední verze z října 2002) stáhnout (samozřejmě zdarma) ze stránek Microsoftu, nebo je součástí balíku, který dostávají předplatitelé vyšších sad MSDN, takže pokud pracujete pro nějakou větší (bohatší) firmu, máte asi toto k dispozici. Tuto aktualizaci lze samozřejmě vřele doporučit (také pro aktualizovanou a stále rozšiřovanou dokumentaci) také vlastníkům Visual C++ .NET. Takže: Ve Windows XP je zavedena nová zpráva CB_GETCOMBOBOXINFO,která nám naplní strukturu COMBOBOXINFO.
typedef struct tagCOMBOBOXINFO {
    DWORD cbSize;
    RECT rcItem;
    RECT rcButton;
    DWORD stateButton;
    HWND hwndCombo;
    HWND hwndItem;
    HWND hwndList;
} COMBOBOXINFO, *PCOMBOBOXINFO, *LPCOMBOBOXINFO;
Význam jednotlivých položek již napovídají jejich názvy:
  • rcItem - obsahuje souřadnice (obdélníka) editačního pole (prvku Edit)
  • stateButton - obsahuje stav rozbalovacího tlačítka ComboBoxu.
  • hwndCombo - handle (okna) ComboBoxu
  • hwndItem - handle (okna) prvku Edit
  • hwndList - handle rozbalovacího pole (ListBoxu)
Podrobný popis této zprávy a struktury naleznete na MSDN, zde si ukážeme příklad jejího použití. Na stisknutí tlačítka zavoláme následující funkci, která nastaví text editačního pole ComboBoxu a dále nastaví vlastní písmo (font) rozbalovacímu poli (ListBoxu). Proto tedy to "divné" písmo na úvodním obrázku. Pro zjednodušení je použit jeden ze systémových fontů, získaných funkcí GetStockObject.
void NaComboInfo(HWND hWnd)
{
  COMBOBOXINFO cbi;
  ZeroMemory(&cbi, sizeof(cbi));
  cbi.cbSize = sizeof(cbi);
  SendDlgItemMessage(hWnd, IDC_COMBO, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi);
  SetWindowText((HWND)cbi.hwndItem, _T("Vlastní text"));
  SendMessage((HWND)cbi.hwndList, WM_SETFONT,
    (WPARAM)GetStockObject(ANSI_FIXED_FONT), TRUE);
}
Doprovodný projekt je ke stažení zde: win_api_combobox_2.zip

Copyright © 2019 - Radek Chalupa