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

Ovládací prvky Windows - úvod.  10.1.2002

V minulých dílech jsme se naučili základům práce s nabídkou okna a s tím souvisejícím zpracováním výběru z nabídky, a v té souvislosti jsem se seznámili se zprávou WM_COMMAND. Dnes se naučíme vytvářet dětská okna, tedy většinou prvky jako tlačítka, editační pole apod. umístěné na hlavním okně.

Na úvod je třeba připomenout, že v běžné praxi programů vytvořených ve Visual C++ se tyto výše uvedené prvky Windows umisťují na dialogová okna. Dialogová okna jsou poněkud jednodušší a méně náročné na systémové zdroje. Proč tomu tak je poznáme v jednom z nejbližších pokračování, kdy se jim budeme věnovat podrobněji. Naopak v aplikacích vytvářených například pomocí knihovny VCL (C++ Builder a Delphi) se dialogová okna v pravém slova smyslu nepoužívají a i formuláře, plnící funkci dialogů jsou ve skutečnosti běžná okna simulující chování standardního dialogu. I přes výše uvedené se však "ruční" vytváření prvků Windows samozřejmě často používá i ve Visual C++, proto začneme tímto tématem, jehož pochopení nám pak dá dobrý základ při používání dialogových oken.

Vytvořme si na našem okně jedno editační pole a 2 tlačítka. Jedno z nich bude ukončovat aplikaci a při stisknutí druhého si někam, konkrétně třeba do message-boxu vypíšeme aktuální obsah editačního pole. Nejdříve si deklarujeme příslušné proměnné typu HWND, udržující handle vytvořených oken:

HWND g_hwndEnd;
HWND g_hwndButton1;
HWND g_hwndEdit;

Vlastní vytvoření těchto prvků provedeme opět pomocí funkce CreateWindowEx. Třídu okna v tomto případě není třeba registrovat, protože pro tyto tzv. Standardní prvky Windows jsou již v systému registrovány příslušné třídy. Potřebné názvy těchto tříd zjistíme v dokumentaci (např. v MSDN u popisu funkce CreateWindowEx). V našem případě půjde o třídy "EDIT" a "BUTTON". Vytvořme si tedy editační pole:

g_hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
  TEXT("EDIT"),
  TEXT("editační pole"),
  WS_CHILD | WS_VISIBLE | ES_LEFT,
  10, 15, 200, 25,
  g_hwndMain,
  (HMENU)NULL,
  g_hInstance,
  NULL);
if ( g_hwndEdit == NULL )
  return FALSE;

Jako parametr dwExStyle použijeme WS_EX_CLIENTEDGE, aby edit-box měl vnořené okraje, jak bývá u tohoto prvku zvykem. V parametru dwStyle je důležitá hodnota WS_CHILD. Říká, že se jedná o dětské okno umístěné v klientské oblasti rodičovského okna uvedeného v parametru hWndParent. Když tuto hodnotu neuvedeme, edit-box se vytvoří jako plovoucí okno s vlastním titulkovým pruhem (při těchto rozměrech ovšem pak na vlastní editační pole zůstanou nějaké 2-4 pixely), s tím že funkčnost zůstane zachována, tj budeme moci do něj psát a získávat jeho obsah. Pokud bychom neuvedli hodnotu WS_VISIBLE, museli bychom po vytvoření edit-boxu ještě pomocí funkce ShowWindow tento zviditelnit. Hodnota ES_LEFT pak určuje zarovnání textu doleva.

Podobně si vytvořme dvě tlačítka:

g_hwndButton1 = CreateWindowEx(0,
    TEXT("BUTTON"),
    TEXT("Text?"),
    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    10, 50, 75, 25,
    g_hwndMain,
    (HMENU)NULL,
    g_hInstance,
    NULL);
if ( g_hwndButton1 == NULL )
    return FALSE;
g_hwndEnd = CreateWindowEx(0,
    TEXT("BUTTON"),
    TEXT("Konec"),
    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    95, 50, 75, 25,
    g_hwndMain,
    (HMENU)ID_END,
    g_hInstance,
    NULL);
if ( g_hwndEnd == NULL )
    return FALSE;

Zde hodnota BS_PUSHBUTTON znamená, že jde o běžné tlačítko. Například check-box je také button s vlastností BS_CHECKBOX. Lze sice říci, že s velkou pravděpodobností je hodnota BS_PUSHBUTTON defaultní, ale vždy je lépe na to nespoléhat a uvést ji.

Nyní tedy máme požadované prvky na okně.

Určitě si všimnete, že písmo takto vytvořených prvků je jiné než u běžných prvků umístěných na dialogovém okně. O fontech a jejich použití se samozřejmě naučíme více později, proto na tomto místě uvedu bez podrobnějšího komentáře jeden způsob, jak nastavit písmo našich prvků na font běžný v grafickém rozhraní Windows.

HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(g_hwndEdit, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
SendMessage(g_hwndButton1, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
SendMessage(g_hwndEnd, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);

Když tento kód přidáme do funkce InitApp za vytvoření oken prvků dostaneme již výsledek, na který jsme zvyklí

Nyní nám již zbývá jen umět reagovat na některé události na těchto prvcích. U zachytávání kliknutí na button máme v zásadě 2 možnosti. Když se podíváte na kód vytvoření tlačítka "Konec", zjistíte, že jsem jako parametr hMenu funkce CreateWindowEx uvedl hodnotu identifikátoru položku menu ID_END. V tomto případě button při stlačení pošle oknu zprávu WM_COMMAND stejně jako menu při vybrání položky. Vzhledem k tomu, že zachycení identifikátoru ID_END již máme hotové, nic dalšího nemusíme do kódu přidávat a stlačení buttonu vyvolá stejnou akci jako vybrání položky menu ID_END ("Konec"). Druhou možností jak identifikovat tlačítko v handleru zprávy WM_COMMAND je test parametru lParam na jeho handle:

case WM_COMMAND:
  if ( lParam == (LPARAM)g_hwndButton1 )
  {
    GetWindowText(g_hwndEdit, chText, 200);
    MessageBox(g_hwndMain, chText, TEXT("Obsah editačního pole"), MB_ICONINFORMATION);
  }

Pro získání obsahu edit-boxu použijeme funkci GetWindowText, která nám naplní parametr lpString textem okna, v případě edit-boxu samozřejmě textem v editačním poli. Třetí parametr (nMaxCount) pak je maximální počet znaků, které se mají kopírovat. Samozřejmě že v našem případě použití textového bufferu s pevnou délkou (200) způsobí uříznutí textu delšího než 200 znaků. Vyřešení tohoto problému pomocí dynamicky alokovaného bufferu je ale už jiné téma.

Tolik pro dnešek a pokud si chcete zaexperimentovat, zkuste si různě měnit hodnoty stylů při vytváření edit-boxu a tlačítek a sledovat výsledek.

Doprovodný projekt (Visual C++ 6) je ke stažení zde: win_api_10.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