V minulé kapitole jsem nastínil dvě otázky. První z nich byla, jaké okno je vlastníkem okna aplikace. Pravda je taková, že jde o okno Desktop. Nakonec je to logické, že :-)?
Druhá otázka byla, jak v MDI aplikaci docílit toho, aby okna potomků měla svá minimalizační a maximalizační tlačítka a aby bylo možno takové maximalizované okno uzavřít jedním kliknutím. Kdo z vás na to přišel, může si směle pogratulovat: řešením je vložit na rodičovský (hlavní) formulář komponentu MainMenu, tedy vytvořit v programu hlavní menu. Zmíněná tlačítka potomků se pak vytvářejí jakoby „na onom“ menu.
A teď už se směle vrhneme do dnešního tématu. Poněkud tajuplný výraz „pouťáky“ neskrývá nic jiného, než pouťové efekty aplikace. Takovým efektem rozumíme třeba barevné tlačítko, obrázek na ploše, změnu kurzoru myši nebo papírek letící do koše při pokusu o výmaz souboru. Tedy vše, čemu se programátoři zpravidla brání, ale čeho si „běžný“ uživatel (a především jeho šéf, který mu bude program kupovat), hned všimne.
Poznámka: Poněkud sporná je otázka, zdali je nápis typu „Systém je zaneprázdněn“ také pouťovým efektem. V tomto ohledu bych vám, drazí čtenáři, dal rád prostor v diskusi pod článkem :-)
Proč se programátoři zuby nehty brání komponování pouťáků do svých aplikací? Nevýhody pouťáků jsou zřejmé:
- zpomalují aplikaci;
- ubírají systémové prostředky;
- berou čas programátorův („proč mám ztrácet čas programováním blikající a pípající animace, když je mnohem důležitější optimalizovat algoritmus?“);
- nesouvisí bezprostředně s řešeným problémem;
- dělají z původně svižné aplikace monstrózní, avšak neefektivní monstrum;
- …atd.
Nevýhod lze najít ještě mnohem víc, ale ať se nám to líbí nebo ne, pouťáky zkrátka aplikaci prodávají. Šéf běžné (ve smyslu nepočítačové) firmy se nebude pídit po tom, kolik geniálních nápadů využil programátor ke zrychlení výpočtu. Když se mu program na první pohled nezalíbí, koupí jej od konkurence, a bude mu jedno, že běží dvakrát pomaleji než ten váš.
Tenhle scénář se netýká jen pouťáků, ale „viditelných“ částí aplikace vůbec, tedy ovládání, struktuře menu, nápovědě, dokumentaci, apod.
Taková je realita. Proto se vší vážností doporučuji v maximální míře dbát na přítomnost pouťových efektů, stejně jako na kvalitu vizuálního rozhraní programu, nápovědy, dokumentace a podobného „balastu“.
Podívejme se, jak snadno a rychle dostat pár pouťáků do aplikace v Delphi a jak obecně vylepšit její vzhled.
Oddělovací čáry – komponenta Bevel
Nejjednodušším, přesto poměrně elegantním způsobem, jak vylepšit vzhled aplikace, je používání oddělovacích čar a rámečků. Pomocí nich vizuálně rozdělíme komponenty na formuláři do logických skupin a celý formulář vypadá mnohem přehledněji.
Komponentu Bevel nalezneme v paletě Additional. Pomocí ní můžeme vytvořit jak pouhou oddělovací čáru, tak rámeček, který navíc může být zapuštěný či vyzdvihnutý. Důležité je, že Bevel (na rozdíl např. od komponenty Panel) se nestává vlastníkem komponent, které na něho umístíme, funguje jen čistě vizuálně.
Důležité jsou dvě jeho vlastnosti: Shape a Style. Vlastnost Shape říká, jak bude Bevel vypadat:
- bsBottomLine – zobrazí se jen jako čára vespod své klientské oblasti;
- bsBox – zobrazí se jako box, v závislosti na hodnotě vlastnosti Style bude zapuštěný (lowered) či vyzdvihnutý (raised);
- bsFrame – klientská oblast bude ohraničena rámečkem (opět lowered nebo raised);
- bsLeftLine – zobrazí se jako čára na levé straně své klientské oblasti;
- bsRightLine – zobrazí se jako čára na pravé straně své klientské oblasti;
- bsSpacer – prázdné místo (nebude vidět nic);
- bsTopLine - zobrazí se jako čára na horní straně své klientské oblasti.
Vlastnost Style říká, zda tvar bude zapuštěný (bsLowered) nebo vyzdvihnutý (bsRaised) u těch nastavení Shape, kde to má smysl.
Tato komponenta nemá žádné události.
Tlačítko s obrázkem – komponenta BitBtn
Dalším typickým pouťákem jsou tlačítka s bitmapou – komponenty BitBtn. Nalezneme je v paletě Additional. Tato tlačítka jsou pokud jde o funkčnost velmi podobná „klasickým“ tlačítkům (komponentám Button). Liší se od něho pouze svým vzhledem, protože obsahuje bitmapu, která by měla na první pohled charakterizovat účel tlačítka.
V Delphi existuje deset předdefinovaných tlačítek, jak je ukazuje obrázek. Kromě nich je ovšem možné vytvořit libovolný jiný vzhled tlačítka – stačí použít bitmapu vhodné velikosti. Pokud chcete, aby velikost vašich vlastních obrázků korespondovala s velikostí těch standardních, používejte bitmapy o velikosti 18 x 18 bodů.
Podívejme se na důležité vlastnosti tlačítek BitBtn:
Vlastnost |
Význam |
Glyph |
Přiřazuje obrázek (bitmapu) k tlačítku. |
Kind |
Určuje druh tlačítka, tedy jeho vzhled. Umožňuje vybrat zmíněná předdefinovaná tlačítka, při zadání hodnoty bkCustom můžete použít libovolný (svůj) obrázek. |
Layout |
Určuje, kde se na tlačítku bitmapa objeví (vlevo, vpravo, nahoře, dole). |
Margin |
Slouží ke stanovení počtu pixelů mezi levým okrajem tlačítka a obrázkem. Hodnota –1 (která je default) říká, že obrázek i s textem (titulkem) bude centrovaný. |
ModalResult |
Velmi použitelná vlastnost: říká, zda (a jak) bude uzavřen modální rodičovský (parent) formulář tlačítka. Nevyžadujeme-li jinou činnost, není vůbec nutné ošetřovat události OnClick tlačítek, stačí jim takto nastavit „výsledek“. |
NumGlyphs |
Říká, kolik obrázků bitmapa obsahuje – viz poznámka pod tabulkou. |
Spacing |
Určuje počet pixelů mezi obrázkem a titulkem (Caption). |
Vlastnost NumGlyphs říká, kolik obrázků obsahuje bitmapa specifikovaná vlastností Glyph. Bitmapa musí splňovat následující podmínky: všechny obrázky musí mít stejnou velikost a musí být umístěny v řadě za sebou. BitButton pak zobrazí jednu z ikon v závislosti na svém stavu:
- Up – zobrazí se u nevybraného tlačítka, u tlačítka, jež má zaměření, a pokud jiný obrázek není;
- Disabled – zobrazí se, nelze-li tlačítko vybrat;
- Clicked – zobrazí se, je-li tlačítko vybráno (je-li zrovan stisknuto);
- Down – zobrazí se, je-li tlačítko trvale stlačeno (to má význam až u tlačítek SpeedButton, která popisuji v další podkapitole).
Jednu z možností, jak získat bitmapu s více obrázky, popíšeme níže v podkapitole věnované seznamu obrázků (StringList).
Nástrojová lišta poprvé – komponenty SpeedButton
Nástrojové lišty jsou v současných aplikacích velmi časté. Umožňují uživateli možnost rychlé volby bez nutnosti proklikávat se strukturou menu.
V Delphi můžeme nástrojovou lištu vytvořit dvěma způsoby. Komplexnější a flexibilnější je použití komponent SpeedButton z palety Additional. Tyto komponenty sdružíme na komponentu Panel (ta je v paletě Standard).
Komponenta SpeedButton je velmi podobná komponentě BitBtn, popisované v předchozí podkapitole. Zobrazuje bitmapu, ale nemůže zobrazit titulek. Stejně jako u BitButtonu může mít více obrázků pro více svých stavů. Zde se také dostává ke slovu „čtvrtý“ stav – Down (stále vybráno).
Důležitá je vlastnost GroupIndex, pomocí níž můžeme sdružovat tlačítka do skupin. Hodnota 0 (která je default) říká, že jde o nezávislé tlačítko. Pokud chceme vytvořit skupinu, nastavíme všem jejím tlačítkům stejnou (nenulovou) hodnotu GroupIndex. Vlastností Down pak můžeme nastavit, které tlačítko bude zpočátku stisknuto.
Pomocí těchto vlastností můžeme zajistit, aby se tlačítka chovala jako CheckBoxy nebo RadioButtony (tedy aby mohlo být stisknuto právě jedno tlačítko, aby mohla být vybrána libovolná kombinace, nebo aby třeba nemuselo být vybráno žádné tlačítko).
Vytvoření nástrojové lišty:
Shrňme tedy, že pokud chceme vytvořit nástrojovou lištu, vložíme nejprve na formulář komponentu Panel z palety Standard. Pak na ní rozmístíme vlastní tlačítka (komponenty SpeedButton z palety Additional) a vhodně si „pohrajeme“ s jejich vlastnostmi GrouIndex, Down, AllowAllUp.
Cimrmanovský úkrok stranou – komponenta ImageList
Abychom se mohli podívat na další možnost, jak vytvořit nástrojovou lištu, musíme si něco říci o komponentě ImageList. Nalezneme ji v paletě Win32. Jejím účelem je shromažďovat kolekci (seznam) obrázků stejné velikosti. Tyto obrázky (bitmapy, ikony…) jsou následně přístupné pomocí indexu.
ImageList můžeme použít k účinné správě velkých, rozsáhlých množin obrázků a ikon. Navíc všechny obrázky ImageListu jsou reprezentovány jako jedna (široká) bitmapa. Pokud vás napadá souvislost s předchozími podkapitolami (tedy používání bitmap obsahující více obrázků – např. komponenta BitBtn), jste na správné adrese. Kromě tlačítek BitBtn a SpeedButton je seznam obrázků využíván i dalšími komponentami, jako např. TreeView, ListView, CoolBar a ToolBar (viz další podkapitola).
Všechny obrázky jsou následně přístupny pomocí indexu v rozsahu 0 až N-1. V návrhové fázi je nejlepší používat nástroj nazvaný Image List Editor. Ten se vyvolá po stisku pravého tlačítka myši na komponentě ImageList, kterou jsme vložili na formulář (viz obrázek).
Nástrojová lišta podruhé – komponenta ToolBar
Pomocí komponenty ToolBar můžeme také vytvořit nástrojovou lištu. ToolBar se nalézá v paletě Win32. Oproti popisovanému nástrojovému pruhu (vytvořeného z Panelu a ze SpeedButtons) umožňuje navíc některé operace a vyznačuje se poněkud jiným způsobem návrhu. Úzce spolupracujeme s komponentou ImageList popsanou v předchozí podkapitole.
Vše si předvedeme pro změnu na příkladu:
- Vložíme na formulář komponenty ToolBar (paleta Win32) a ImageList (paleta Win32).
- Pravým tlačítkem klikneme na komponentu ImageList a zvolíme Image List Editor…
- V otevřeném okně (viz předchozí obrázek) tlačítkem Add… přidáme do seznamu požadované obrázky (je možné vybírat bitmapy *.BMP a ikony *.ICO). Tlačítkem OK uzavřeme Image List Editor.
- Levým tlačítkem klikneme na komponentu ToolBar. V Object Inspectoru nastavíme její vlastnost Images na seznam reprezentovaný komponentou ImageList.
- Pravým tlačítkem klikneme na komponentu ToolBar. Vybereme New Button. Tento krok opakujeme, dokud nevytvoříme kompletní strukturu ToolBaru (nezapomeňte občas vložit New Separator, aby se na vytvořený pruh dalo také dívat:-)).
- Při opakování předchozího bodu se již automaticky tlačítkům postupně přiřazovaly ikony z ImageListu. Pokud nám tento „default“ stav nevyhovuje, není problém jej libovolně modifikovat, a to nastavením vlastnosti ItemIndex každého z tlačítek na ToolBaru (tedy ToolButtons).
Vidíme, že vytvoření nástrojového pruhu tímto způsobem je velmi flexibilní. Navíc ToolBar umožňuje některé další „bonbónky“, o kterých se ovšem zmíním již jen telegraficky:
- Pomocí vlastností DisabledImages a HotImages můžeme určit, které obrázky se budou zobrazovat na nepřístupných, resp. aktivních tlačítkách.
- Můžeme také určovat, jak to bude s možností označovat více než jedno tlačítko zároveň (tedy vytvářet skupiny tlačítek – vlastnost Grouped).
- Pomocí vlastnosti MenuItem můžeme přiřadit jednotlivým ToolButtonům položky hlavního menu.
- Vlastností Style můžeme poměrně významně modifikovat styl zobrazení (ale i chování tlačítka).
Záložky – komponenty TabControl a PageControl
V Delphi můžeme se záložkami pracovat dvěma různými způsoby. Buď použijeme komponentu TabControl nebo PageControl. Přestože na první pohled rozdíl nepoznáte, funkčnost je zcela odlišná.
TabControl slouží pouze k definici vlastních záložek. Ve své horní části zobrazuje seznam záložek, ale sám (trochu paradoxně) žádné karty nemá: pokud umístíte na jednu „kartu“ (použil jsem uvozovky, protože fyzicky tam žádná karta vlastně není) jakýkoliv ovládací prvek (komponentu, např. editační pole), bude zobrazeno bez rozdílu na všech „kartách“. Z toho vyplývá, že je nutné naprogramovat reakci na výběr (změnu) záložky.
Naproti tomu PageControl obsahuje vlastní (rozlišné) listy záložek. Ty mohou obsahovat své (vlastní) komponenty a ovládací prvky, jako např. editační okna, tlačítka, apod. Pokud vložíte některou ikonu na jednu kartu, bude skutečně jen na příslušné kartě, nikoliv (zdánlivě) na všech.
Z těchto rozdílů vyplývá také rozdíl v práci a v návrhu těchto dvou komponent.
TabControl U komponenty TabControl se záložky spravují ve vlastnosti Tabs. Tato vlastnost je (nám již dobře známého) typu TStrings, takže v době návrhu je také k dispozici String List Editor. Pro Tabs tedy také fungují všechny metody, které jsme si popisovali v souvislosti s typem TStrings (viz Umíme to s Delphi, 8. díl). Vlastnost TabIndex definuje aktuálně vybranou záložku.
U komponenty TabControl stojí za zmínku také událost OnChanging, v níž je možné zabránit přesunu na jinou záložku (např. můžete otestovat platnost údajů, které uživatel vyplnil do jednotlivých editačních polí, apod.). Používá se parametru AllowChange. V následujícím příkladu např. zakážeme přechod na jinou záložku, pokud je v editačním poli edtUserName slovo „Administrator“, protože nechceme povolit vytvoření uživatele s tímto uživatelským jménem. Komponentě TabControl jsem ponechal původní jméno, ač vím, že je to odsouzeníhodné:
procedure TwndHlavni.TabControl1Changing(Sender: TObject;
var AllowChange: Boolean);
begin
AllowChange := (edtUserName <> `Administrator`);
end;
PageControl Všimněte si, že jednotlivé listy vytvářejí fyzicky nové komponenty (jmenují se TabSheet a jsou typu TTabSheet). To sice poněkud komplikuje správu, ale zase to umožňuje nastavovat (a navrhovat) individuálně každou z nich.
U komponenty PageControl není k dispozici žádný editor, který by umožňoval editovat seznam záložek. V době návrhu přidáme list se záložkou tak, že na PageControl klikneme pravým tlačítkem a vybereme New Page. S každou vytvořenou stránkou následně můžeme zacházet jako se zcela samostatným, autonomním objektem.
Domácí úkol: zkuste vymyslet, jak přidat novou stránku za běhu programu.
Vybranou stránku definuje vlastnost ActivePage. Tato vlastnost je typu TTabSheet (používáme tedy přímo danou stránku, nikoliv index či jiný typ „ukazovátka“). K přechodu na další, resp. předchozí stránku stačí zavolat metodu komponenty PageControl SelectNextPage.