Umíme to s Delphi, 9. díl - uživatelská menu

Vytváříte-li jakoukoliv (byť jen trochu rozsáhlejší) aplikaci, asi se neobejdete bez jednoho z klíčových ovládacích prvků. V dnešním díle seriálu se podíváme ne tvorbu uživatelských nabídek (menu).
Řešení domácích úkolů z minulého dílu

Nejprve si řekneme, jaké je řešení domácích úkolů:

Stačí v návrhu nastavit komponentě Timer (časovači) vlastnost Enabled = False a do události OnClick přidaného tlačítka napsat

Timer1.Enabled := True;

Časovač se pak spustí po stisku tlačítka a vzápětí se „rozjedou“ i Gauge a ProgressBar.

V Delphi 3 byla zkompilována aplikace, kterou ukazuje první obrázek (ListBox). Poznáte to podle odlišné ikonky v rohu :).

Důvodem toho, že oba for-cykly běží od jedničky, je fakt, že nechceme čísla vypisovat do „fixed“ buněk, které je lépe použít třeba k nadpisu apod.

Zásady tvorby hlavního menu

V aplikaci můžeme samozřejmě mít více typů menu. Nejdůležitější bývá hlavní menu, které je umístěno zpravidla úplně nahoře v okně. Zdálo by se, že k hlavním uživatelským menu není obecně co dodat. Opak je však pravdou, neboť jeho vytvoření si komentář rozhodně zaslouží. V následujícím textu shrnu některá fakta, která je vhodné respektovat (nebo se jim naopak vyhnout) při vytváření menu. Pokud patříte k vývojářům, kteří už nějaké ty aplikace vytvořili, asi vás bude následující text trochu nudit, neboť buďto už to všechno víte, nebo se tím řídit stejně nehodláteJ.

Druhy položek menu

Nejprve se podíváme, jaké druhy položek může hlavní menu obsahovat:

  • Příkazy: položky používané k udělení rozkazu pro spuštění akce. Nejsou nijak opticky rozlišeny.
  • Nastavení: položky používané k vypnutí nebo zapnutí volby. Povolení volby je opticky odlišeno zatrhávacím „véčkem“ v levé části položky.
  • Dialogy: položky způsobující objevení dialogu (otevření dalšího okénka). Měly by se odlišovat třemi tečkami za textem položky, což sice není přísně vzato nutné (poněvadž text položky píšeme sami), ale je rozhodně dobré tuto konvenci dodržovat.
  • Vnořené: položky způsobující slouží rozvinutí další úrovně menu – viz dále. Odlišují se trojúhelníčkem v pravé části.

Obecné poznámky a konvence související s návrhem menu:

Položku menu je možné vložit přímo do pruhu s menu (viz obrázek, položka Zavři vše!). Tomuto způsobu je ale vhodné se vyhnout. Uživatelé totiž vybírají součásti pruhu z menu z důvodu prozkoumání struktury. Málokdo předpokládá, že by se mohl rovnou spustit příkaz. V případě, že se přesto rozhodnete vložit příkaz přímo do pruhu, vložte za něho alespoň vykřičník. Stále ale tvrdím, že je lepší vytvořit pro příkaz jedno rozvinutelné menu s jedinou položkou.

Umístění rozvinutelného menu do jiného rozvinutelného menu (rozvinutí ve dvou úrovních) je velmi běžné; ve Windows se v takovém případě objeví vizuální nápověda – malý trojúhelníček na pravé straně. Tento typ položek menu je ale vhodný jen pro zřídka používané příkazy. Častější výběr takové položky je totiž zdlouhavý. Někdy bývá lepší místo vytváření vnořené úrovně umístit skupinu přímo do hlavní úrovně menu a její položky oddělit čarami.

Už vůbec není vhodné používat větší množství zanoření. Nainstalujete-li si někdy aplikaci s více než dvěma úrovněmi zanoření, velmi brzy otestujete kvalitu odinstalačního programu této aplikace.

Větší opatrnost je třeba také při změnách popisů (položek) za běhu programu. Pokud například máte v menu položku Zobraz tabulku, je vhodné poté, co uživatel tuto položku zvolí, změnit její text na Skryj tabulku. Není ale příliš chytré měnit položky „brutálním“ způsobem, tedy nedržet se jejich logického významu a změnit třeba Zobraz tabulku na Zobraz seznam. Pro uživatele neexistuje příliš více matoucích akcí.

Jednou z nich ovšem je skrývání položek menu. Pokud se rozhodnete některou z položek zakázat (což je běžné), udělejte to nastavením Enabled na false (položka bude šedá, nebude ji možno vybrat, ale fyzicky bude na tomtéž místě v menu). Pokud položku zcela skryjete (Visible = false) a pokud něco takového občas periodicky zopakujete, stane se menu zcela nepoužitelným. Uživatelé totiž často hledají položky „popaměti“, jen podle jejich pozice.

Položky v menu by měly být logicky členěny do sekcí (vodorovnými čarami). Maximální počet položek v jedné sekci by rozhodně neměl přesáhnout šest.

Důležité je také dodržování standardní struktury menu. Určitě víte, že ve většině windowsových aplikací je menu jakoby „podle stejného mustru“. V souladu s principem prvořadosti uživatele je nutné uživateli vyjít vstříc používáním takových ovládacích prvků, které dobře zná. Pruh menu by měl začínat položkou Soubor, následovat by měly Úpravy, Zobrazit apod. Menu by mělo končit položkami Možnosti, Nástroje, Okno. Úplně poslední by měla být Nápověda. Navíc každé z těchto podmenu má specifické řazení položek (např. menu Soubor vypadá takto: Nový, Otevřít, Uložit, Uložit jako…, Nastavení tisku, Tisk, Konec (samozřejmě se tato struktura může lišit aplikace od aplikace, ale je dobré dodržovat alespoň jakousi základní linii).

Dalším bodem je používání klávesových zkratek. Jedním typem jsou „standarní“ zkratky typu Ctrl+C, Ctrl+V. Platí zcela totéž, co v předchozím případě (tedy neměnit zaběhnuté scénáře). Pokud v textovém editoru nastavíte pod zkratku Ctrl+C zavření dokumentu, příliš uživatelů nepotěšíte. Druhým typem klávesových zkratek jsou Alt+písmeno, která způsobí vybrání položky menu začínající tímto písmenem.

S tím souvisí další otázka – jazyková. Moje doporučení zní: děláte-li aplikaci pro využití v Česku, udělejte menu české. Jsme Češi, pišme česky a nestyďme se za to. Chcete-li svůj produkt šířit do zahraničí, vytvořte jazykové mutace. Kromě nesporného přínosu pro uživatele to vašemu programu dodá nádech profesionality. Naopak nedoporučuji „překládat“ klávesové zkratky. Uživatelé zpravidla znají ono Ctrl+C, a změníte-li to na Ctrl+K, bude to víc ke škodě než k užitku.

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

Ještě dodatek ke zmíněným jazykovým mutacím: řešit to lze buď tak, že se text položek menu načte z nějakého souboru (např. textového), nebo je menu v samostatném modulu aplikace, a nebo se vytvářejí spustitelné soubory s menu pro každý jazyk zvlášť, přičemž každý způsob má své výhody a nevýhody.

Konečně Delphi

Dostáváme se k tomu, jak vytvořit menu v naší aplikaci. Je to jednoduché a v Delphi za tím účelem existuje výkonný Menu Designer (viz obrázek, omlouvám se za prohřešek proti štábní kultuře – při vytváření tohoto příkladu jsem zapomněl přejmenovat formulář).

Umístěte na formulář komponentu MainMenu z palety Standard. Umístit ji můžete kamkoliv, protože se stejně zobrazí jen malý čtvereček (který bude samozřejmě za běhu skryt) a menu bude na správném místě. Když na tento čtvereček dvakrát kliknete, otevře se Menu Designer. V něm navrhujete vše podstatné. Kliknete na místo nové položky a napíšete její popis. Tím nastavíte její vlastnost Caption (každá položka menu má své vlastnosti viditelné v Object Inspectoru). Vlastnost Name se také nastaví automaticky, je ovšem na vás, budete-li zachovávat štábní kulturu a položky „správně“ přejmenovávat (v hodně rozsáhlém menu je to samozřejmě poměrně brutální úkol).

Menu vytvářené v Menu Designeru vypadá stejně, jako bude vypadat výsledná (run-time) podoba, s tím rozdílem, že samozřejmě vidíte všechny položky, tedy i položky s vlastností Visible = False, a navíc nevidíte význam vlastnosti Break (viz dále).

Všechny položky menu mají jedinou událost: OnClick. Do jejího těla napíšete kód, který se má provést při vybrání položky.

Chcete-li některou položku použít k rozbalení dalšího podmenu, klikněte na ni pravým tlačítkem a zvolte „Create Submenu“ (je to jen jedna z možností).

Chcete-li položky v menu opticky rozdělit vodorovnou čárou (což vypadá skvěle, pokud to nepřeženete a nebudete oddělovat každou druhou), jednoduše uveďte jako Caption položky pomlčku (-), ve výsledku bude tato položka vypadat právě jako ona čára.

Je dobré vědět, jak nastavíte „aktivní“ písmeno položky (tedy jak např. zařídit, že položka „Otevři“ se vybere stiskem Alt+O). Je to také snadné – jednoduše napište před zvolené písmeno znak & (např. &Otevřít, nebo Uložit j&jako).

Domácí úkol: zkuste vymyslet, co dělat, chceme-li mít znak & přímo v textu položky menu (např. „Vašek & Eva“).

Můžete používat také tzv. šablony menu. Dostanete se k nim také pravým tlačítkem a vybráním „Insert From Template“. Tyto šablony obsahují poměrně dost „standardizovaných“ menu (např. menu Files apod.), takže se nemusíte trápit s vypisováním všech položek. Takto vytvořené menu samozřejmě můžete dále upravovat a následně opět uložit jako šablonu pro příští použití. Jediným problémem tak zůstává, že standardní šablony obsahují samozřejmě pouze anglická menu.

Podívejme se na vlastnosti položky menu:

Vlastnost Význam
Break Na tuto vlastnost raději zapomeňte (viz dále).
Checked Je-li vedle položky zobrazeno zatrhávací „véčko“. Je to velmi elegantní metoda, jak do menu zakomponovat „povolovací“ položky.
Default Málo používaná, přitom vcelku praktická vlastnost. Nastavení položky v podmenu jako Default znamená, že pokud uživatel poklepe na položku, která toto podmenu rozbalí, bude to bráno jako vybrání této „Default“ položky.
Enabled Již zmíněná vlastnost „povolující“ položku. Zakážete-li položku, bude šedá a nebude ji možno vybrat.
GroupIndex Slouží k logickému „rozčlenění“ položek menu.
RadioItem Slouží k nastavení položky jako „výlučně vybratelné“. Příklad viz níže.
ShortCut Specifikuje klávesovou zkratku této položky, příklad viz níže.
Visible Slouží k nastavení položky jako neviditelné. Má mnohdy praktický význam, ne však za účelem opakovaného skrývání a odkrývání položky před uživatelovýma očima.

V tabulce jsem několikrát slíbil, že níže něco blíže vysvětlím či předvedu. Ten okamžik právě nastal:

Vlastnost Break

Ne, prosím, tuto vlastnost raději nepoužívejte… Nastavíte-li u některé položky vlastnost Break na mbBreak, příp. mbBarBreak, zobrazí se tato položka v následujícím sloupci / na následujícím řádku. Je to odporné a používejte to jen k demonstraci toho, jak by menu vypadat nemělo (viz obrázek).

RadioItem, GroupIndex

Nastavíte-li některým položkám stejnou hodnotu GroupIndex a RadioItem = True, bude možno vybrat (zatrhnout, Checked) pouze jednu z nich. V takovém případě budete ale sami muset nastavovat vlastnost Checked, i když ta se u „normálních“ položek nastavuje sama podle toho, kam uživatel klikne.

Klávesové zkratky

V době návrhu nejsnáze vložíte klávesovou zkratku tak, že ji vyberete v Object Inspectoru, kde je k dispozici nepřeberné množství zkratek. Při běhu programu je to trochu obtížnější. Příkladem hodnoty je Ctrl+C. Zadáte ji takto:

MnItmOtevri.ShortCut := ShortCut(Word(`O`), [ssCtrl]);

Zkratka se vedle položky v každém případě objeví (vypíše) automaticky.

Již jsem se zmínil o tom, že není dobré manipulovat s položkami menu za běhu programu (přeskupovat, skrývat, přejmenovávat apod.). Přesto občas nastává situace, kdy potřebujeme použít jiné položky v menu nebo celé úplně jiné menu. Typicky jde o přítomnost dvou typů menu (pro „začátečníky“ a „pokročilé uživatele“). V takovém případě si prostě vytvořte dvě rozdílná menu (na formulář umístěte dvě komponenty MainMenu), jedno z nich nastavte jako implicitní (vlastnost Menu formuláře) a někam (klidně i do menu) přidejte příkaz zobrazující druhé menu.

Položky menu mají poměrně dost slušné množství metod. Jednou z nich je např. Add, která přidá položku na konec menu. Příklad:

procedure Form1.Button1Click(Sender: TSender);

var
  MnItmNovaPolozka: TMenuItem;

begin
  mnItmNovaPolozka := TMenuItem.Create(Self);
  mnItmNovaPolozka.Caption := `Nová položka`;
  MnItmFile.Add(mnItmNovaPolozka);
end;

V souvislosti s metodou Add možná stojí za úvahu, co dělat, potřebujeme-li za běhu přidat do menu nějakou položku. Pokud už to potřebujete, máte (hrubě rozděleno) tři možnosti:

  • Dodat položku do programu výše uvedeným postupem (existuje např. metoda Insert, která umožní vložit položku jinam než na konec). Problém může nastat v souvislosti s metodou OnClick, kterou potřebujete ošetřit.
  • Vytvořit několik různých menu obsahující položky podle nějakého klíče a ty pak za běhu zaměňovat – detaily jsou vysvětleny výše.
  • Vytvoříte jedno „velké“ menu, do něho „našlapete“ všechny položky a pak jen „kouzlíte“ s vlastností Visible.
Každopádně se při změnách položek menu příliš nerozšoupněte.

Lokální (pop-up) menu

V poslední době se snad nevyskytuje nová aplikace, která by neobsahovala pop-up menu (lokální menu, kontextové menu, dokonce jsem zaznamenal vpravdě příšerný výraz vyskakovací menu). Otevře se zpravidla po stisku pravé klávesy myši. Jeho kouzlo spočívá hlavně v tom, že obsahuje právě takové položky, které jsou v daném okamžiku aktuální (vztahují se k vybranému elementu).

Delphi poskytuje komponentu PopupMenu. Je dosti podobná komponentě MainMenu, a to jak vizuálně (čtvereček), tak způsobem práce (stejný Menu Designer).

Proto nebudeme zabíhat do podrobností. Jediné, co vysvětlíme, bude zajištění toho, aby se v každém okamžiku otevřelo vždy to „správné“ kontextové menu. Zařídí se to tak, že dané komponentě (např. formuláři, editačnímu oknu, memu…) nastavíme jako hodnotu jeho vlastnosti PopupMenu název odpovídajícího kontextového menu (musíme tedy v aplikaci samozřejmě mít více komponent PopupMenu).

Celá komponenta PopupMenu má navíc (od MainMenu) jednu vlastnost a jednu metodu. Vlastnost se jmenuje AutoPopup a její hodnota True (implicitní) znamená, že se menu objeví po stisku pravého tlačítka myši, tedy tak, jak jsme zvyklí. Zakážeme-li „vynořování“ menu (tedy AutoPopup = False), menu se nezobrazí a vyvolat ho lze jen programově jeho metodou Popup. Přidaná metoda komponenty PopupMenu se jmenuje OnPopup a do jejího těla napíšeme kód, který se má vykonat, „vynoří-li se“ (otevře) kontextové menu.

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

Událost OnPopup je generována těsně předtím, než se menu rozbalí. Můžete tedy například otestovat nějaké konkrétní nastavení a podle něho upravit položky v menu.

O položkách kontextového menu platí beze zbytku to, co bylo řečeno k položkám hlavního menu.

Příště výjimky

Tolik tedy k seznámení s uživatelskými nabídkami. V příštím díle se konečně podíváme na něco „vypečenějšího“, konkrétně na výjimky.
Diskuze (10) Další článek: Webové povstání proti podvádějícím ovladačům Asusu

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