Umíme to s Delphi, 49. díl – pohrajte si s formulářem

Formulář je komponentou z nejortodoxnějších. Pomocí formuláře vytváříme uživatelské prostředí aplikace, na formuláři probíhá kompletní návrh uživatelského prostředí. Přestože jsme se již formulářem zabývali, dosud jsme si zdaleka neukázali všechny možnosti. Dnes to napravíme – tento díl seriálu je zaměřen na detaily práce s formulářem.
Ikona formuláře a celé aplikace

Na úvod si ukážeme jeden z nejčastějších způsobů, jakými vývojáři odlišují jednu aplikaci od jiné. Jedná se o změnu ikony formuláře či aplikace. Pokud neurčíte jinak, Delphi všem aplikacím (a tedy jejich hlavním formulářům) přiřadí tutéž (standardní) ikonu. K nastavování ikony formuláře slouží vlastnost formuláře Icon typu TIcon. Abyste mohli změnit ikonu, musíte nějakou mít (tj. vhodný soubor ve formátu *.ICO).

Kromě změny ikony formuláře můžeme ovšem také měnit ikonu reprezentující celou aplikaci – např. na hlavním panelu Windows. Pokud zvolíte nějaký soubor a nastavíte jej jako hodnotu vlastnosti Icon formuláře, změníte pouze ikonu tohoto formuláře, nikoliv celé aplikace (všimněte si, že na hlavním panelu ve Windows zůstala původní ikona). Ke změně ikony aplikace použijte položku hlavního menu Project – Options…, karta Application, tlačítko Load Icon.

Co ale dělat v případě, že nemáte k dispozici žádnou vhodnou ikonu? První možnost je stáhnout nějakou z Internetu, při troše snahy jistě nebude problém nalézt stránku s mnoha dostupnými ikonami (namátkou např. http://www.zeldman.com/icon1.html či http://www.coolarchive.com/icons.cfm).

Pokud ale na Internetu hledat nechcete, případně je vaše aplikace natolik originální, že žádná existující ikona pro ni není dost dobrá :-), nezbývá, než nakreslit si ikonu vlastní. Delphi za tím účelem disponují nástrojem Image Editor. Tento nástroj sice není úplně ideální a bývá relativně často (a upřímně řečeno – také celkem právem) kritizován pro své mizivé možnosti, nicméně pro naše účely nyní postačí. Image Editor otevřete z hlavní nabídky Delphi (Tools – Image Editor). Nástroj se spustí a následně vyberte z jeho hlavní nabídky File – New – Icon File. Otevře se dialog pro výběr vlastností ikony, viz obrázek. Ponechte prozatím standardní nastavení, tedy „velkou“ ikonu (32 x 32 bodů) a 16 barev.

Klepněte na OK a zobrazí se návrhová plocha pro ikonu. Nyní nastala ta pravá chvíle, ve které se můžete dostatečně „vyřádit“. Ovládání Image Editoru je podobné jako ovládání všech dalších grafických editorů. V levé části máte návrhovou plochu a v pravé části vidíte ikonu ve výsledné velikosti. Až budete mít ikonu vytvořenou, vyberte File – Save a ikonu uložte.

Programy ve Windows však mají obvykle dvě ikony. Jednu (velkou, 32 x 32 bodů) pro zobrazení na ploše a třeba v Průzkumníkovi (při volbě Zobrazit – Velké ikony) a druhou (malou, 16 x 16 bodů) kvůli panelu nástrojů, záhlaví okna, Průzkumníkovi (Zobrazit – Malé ikony, příp. Seznam nebo Podrobnosti) a dalším programům, např. Windows Commanderu :-). Velkou ikonu máte už hotovou, ale malou je teprve nutné vyrobit. Klepněte proto v Image Editoru na tlačítko New… Otevře se opět dialog pro výběr vlastností ikony, nicméně nyní už automaticky nabízí malou ikonu. Klepněte proto na OK a vytvořte grafický návrh. Pak zvolte File – Save (nebojte se, nevadí, že se ikona uloží do stejného souboru jako předchozí – velká – ikona, v souboru pak budou obě).

Nyní můžete Image Editor uzavřít a vrátit se do prostředí Delphi. Vytvořenou ikonu můžete přiřadit jen formuláři nebo celé aplikaci (viz výše). Zkuste si přiřadit ikonu celé aplikaci a sledujte, kde se ve Windows objevuje velká a kde malá varianta.

Události formuláře

Když už jsme se dostali k formuláři a poměrně podrobně jej začali rozebírat, vrátíme se na okamžik i k jeho událostem. Podobně jako pro vlastnosti, i u událostí platí, že některé jsou pro formulář zcela unikátní a u ostatních komponent je nenalezneme. S řadou z nich jsme se již setkali v předchozích dílech, nicméně zřejmě neuškodí provést definitivní shrnutí:

Událost: OnActivate

Dojde k ní: stane-li se okno/dialog aktivním

Poznámka: Je generována, přepne-li se uživatel do okna z jiného okna téže aplikace, nikoliv z jiné aplikace.

Událost: OnDeactivate

Dojde k ní: přestane-li být okno/dialog aktivním

Poznámka: Je generována, přepne-li se uživatel do jiného okna téže aplikace, nikoliv do jiné aplikace.

Událost: OnClose, OnCloseQuery

Dojde k ní: je-li formulář zavřen (např. pomocí Alt-F4, tlačítka s křížkem v pravém horním rohu, pomocí systémového menu, ale i programově)

Poznámka: Při zavírání formuláře je nejprve generována OnCloseQuery, poté OnClose. První se používá např. pro potvrzení („Chcete opravdu skončit?“) nebo pro výzvu k uložení dat. Nicméně i v OnClose je ještě šance zavření zabránit a pomocí parametrů lze dialog třeba jen skrýt či minimalizovat.

Událost: OnCreate, OnDestroy

Dojde k ní: při vytvoření, resp. zrušení formuláře

Poznámka: Potřebujete-li zařídit nějaké akce při startu aplikace (resp. při jejím ukončení), bývá vhodným místem právě obsluha události OnCreate (resp. OnDestroy). Také v našem seriálu jsou ve většině ukázkových aplikací úvodní inicializace (např. nastavení titulků a dalších vlastností komponent) prováděny v obsluze události OnCreate hlavního formuláře.

Událost: OnShow, OnHide

Dojde k ní: při zobrazení, resp. skrytí formuláře

Poznámka: Tyto události úzce souvisí s vlastností formuláře Visible.

Událost: OnHelp

Dojde k ní: při žádosti o nápovědu

Událost: OnPaint

Dojde k ní: při překreslení formuláře.

Poznámka: Formulář je překreslen vždy, když dojde k nějaké „vnější“ modifikaci jeho vzhledu na obrazovce. První událost OnPaint je tedy generována už při jeho vytvoření. Další události OnPaint se objevují třeba v okamžiku, když přes příslušné okno přetáhnete jiné okno, když se změní velikost okna (a je nutné překreslit nějaké ovládací prvky), když je okno maximalizováno či obnoveno, apod. V obsluze této události je nutné ručně zajistit překreslení všech uživatelsky kreslených prvků.

Poznámka pro pokročilé uživatele:

Při vytváření viditelného formuláře (např. při startu aplikace, vlastnost Visible = True) , je sekvence generovaných událostí následující:

  • OnCreate
  • OnShow
  • OnResize
  • OnActivate
  • OnPaint

    Při opačné akci, tedy při ukončování aplikace (nebo při uzavírání formuláře) vypadá sekvence událostí takto:

    • OnCloseQuery
    • OnClose
    • OnDeactivate
    • OnHide
    • OnDestroy

    Je tedy zřejmé, že pokud například potřebujete při ukončování aplikace provést nějakou triviální činnost, která není závislá na existenci formuláře a jeho komponent (například zapsat nějaký záznam do losovacího souboru), je zcela lhostejné, jakou si k tomu vyberete obsluhu události. Někdy přesto nastává situace, ve které je vhodné posloupnost událostí znát.

    Metody formuláře

    V závěru povídání o formuláři se podívejte na několik jeho podstatných metod. Některé z metod uvedených v následující tabulce jsou přímo metodami formuláře, některé jsou k dispozici díky dědičnosti (formulář je zdědil od některého ze svých předků). Většinu jsme již poznali:

    Metoda Význam
    Close Uzavře formulář (nejprve zavolá metodu CloseQuery() k ověření, smí-li se formulář zavřít. Pokud CloseQuery() vrátí false, uzavření se neprovede).
    CloseQuery Testuje, může-li se formulář uzavřít.
    Hide Skryje formulář (stále existuje, ale není viditelný).
    Print Vytiskne formulář.
    Show Zobrazí formulář (byl-li skryt).
    ShowModal Zobrazí formulář (byl-li skryt) modálně. Tato metoda vrací hodnotu podle vlastnosti ModalResult formuláře.

    Formulář nemusí být jen pravoúhelníkový

    V mnoha internetových diskusích se objevuje řešení jednoho problému souvisejícího s formuláři. Je to už tak trochu kultovní otázka: jak vytvořit kruhový (či jinak zběsilý) formulář? Přestože tato otázka nespadá tak úplně do koncepce našeho seriálu, jehož cílem je naučit čtenáře konvenční možnosti Delphi (a nikoliv předvádět magii s neomezenými možnostmi Windows API), pro zajímavost si řešení tohoto bonbónku ukážeme.

    Abychom mohli vytvořit formulář jiného než standardního (tedy čtvercového či obdélníkového) tvaru, je nutné zabrousit mimo prostředky Delphi a zalovit v kalných vodách Windows API. Lov je ovšem v tomto případě mimořádně jednoduchý. Vysvětlíme si všechny úlovky, které upotřebíme:

    • datový typ HRGN: tento datový typ Windows API označuje handle na určitou oblast (tato oblast může mít v podstatě libovolný tvar, přesněji řečeno – proměnná typu HRGN může být spjata s jakýmkoliv tvarem);
    • funkce CreateEllipticRgn: tato funkce Windows API vytváří oblast eliptického tvaru. Funkce má čtyři parametry označujíc dva rohy obdélníku, jemuž je tato elipsa vepsána (pořadí parametrů: levý horní roh x, levý horní roh y, pravý dolní roh x, pravý dolní roh y). Návratovou hodnotou je handle na vytvořenou oblast. Oblast vytvořená touto funkcí nám bude sama o sobě ještě k ničemu (nezískáme žádnou fyzicky existující oblast, kterou bychom mohli spatřit někde na pracovní ploše), nicméně pomocí další funkce přinutíme Windows, aby požadované okno vykreslily právě ve tvaru této oblasti.
    • funkce SetWindowRgn: tato funkce Windows API nastavuje zadanou oblast pro zadané okno. Funkce má tři parametry (handle na okno, handle na oblast a logický údaj říkající, má-li se ihned po zavolání funkce provést překreslení okna). Zavoláním této funkce (při povoleném překreslení) způsobí, že okno na obrazovce získá stejný tvar, jako je specifikovaná oblast.
    Protože uvedené dvě funkce nespadají do Delphi, nenaleznete jejich popis v nápovědě (pouze pokud máte nainstalovanou nápovědu Windows SDK). Ukážeme si tedy pro jistotu hlavičky těchto dvou funkcí:

    HRGN CreateEllipticRgn(
      int nLeftRect,  // x-souřadnice horního levého rohu opsaného čtyřúhelníku
      int nTopRect,    // y-souřadnice horního levého rohu opsaného čtyřúhelníku
      int nRightRect,  // x-souřadnice dolního levého rohu opsaného čtyřúhelníku
      int nBottomRect  // y-souřadnice dolního levého rohu opsaného čtyřúhelníku
    );

    int SetWindowRgn(
      HWND hWnd,    // handle okna
      HRGN hRgn,    // handle oblasti
      boolean bRedraw  // příznak překreslení
    );

    Poslední informací, kterou potřebujeme vědět, je skutečnost, že formulář (tedy objekt třídy TForm, stejně jako všechny další komponenty odvozené od WinControl) má vlastnost Handle, která uchovává handle okna.

    Ukážeme si nyní jednoduchou funkci (je to obsluha události OnClick tlačítka btnKouzlo), která způsobí změnu hlavního formuláře aplikace na kruh.

    procedure TfrmHlavni.btnKouzloClick(Sender: TObject);
    var
      Oblast: HRGN;

    begin
      Oblast := CreateEllipticRgn(0, 0, frmHlavni.Width, frmHlavni.Height);
      SetWindowRgn(frmHlavni.Handle, Oblast, True);
    end;

    Výsledek tohoto experimentu si můžete na následujícím obrázku prohlédnout sami:-)

    Důležité je nastavit velikost ohraničující oblasti právě rovnou velikosti formuláře, jinak nebude výsledek dobře vypadat. Zkuste si také změnit hodnotu True ve volání funkce SetWindowRgn. Pak program spusťte, klepněte na tlačítko Kouzlo a zkuste oknem pohnout. Docílíte tím velmi zajímavých efektů:-)

    Poslední maličkostí, kterou si dnes ukážeme, je odstranění hlavního pruhu tohoto eliptického okna. K tomu už využijeme ryze Delphi prostředků (a pokud jste důkladně četli dnešní díl seriálu, měli byste na to přijít už sami). Do uvedené obsluhy události přidáme jeden řádek (v následujícím výpisu je označen tučně):

    procedure TfrmHlavni.btnKouzloClick(Sender: TObject);
    var
      Oblast: HRGN;

    begin
      frmHlavni.BorderStyle := bsNone;
      Oblast := CreateEllipticRgn(0, 0, frmHlavni.Width, frmHlavni.Height);
      SetWindowRgn(frmHlavni.Handle, Oblast, True);
    end;

    Výsledek vypadá skutečně originálně, zvláště v případě, že ještě dostatečně šíleně změníme barvu formuláře (vlastnost Color):

    Kdyby vám tenhle flek někdo ukázal vytištěný na papíře, věřili byste, že jde o okno systému Windows:-)?

    Na závěr

    Dnes jsme se zaměřili na komponentu z nejdůležitějších – na formulář. Závěrečná podkapitola jen podtrhla šíři možností, kterými se v Delphi můžeme bavit. Důležité je, že v Delphi zdaleka nejsme omezeni jen možnostmi Delphi jako takového (možnosti každého vývojového nástroje jsou přece jen nějakým způsobem omezené), ale je možné používat veškerou sílu nástrojů, funkcí, typů a tříd rozhraní Windows API. Jediný problém tak spočívá v tom, že rozhraní Windows API je skutečně mohutné a je poměrně obtížné jej dokonale zvládnout. Jako optimální možnost pro neprofesionály se tedy jeví vhodná kombinace – používání dostupných možností Delphi a v případě potřeby si „vypomoci“ některým prvkem Windows API.

    Věřím, že jste informace uvedené v dnešním a předchozím díle chápali jako lehčí odpočinek po náročnějším tématu (vytváření komponent), nicméně doufám, že jste je shledali zajímavými.

Diskuze (3) Další článek: Trampoty s expozicí

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , , ,