Menu a dialogy

Ve všech předcházejících projektech jsme pro jejich ovládání používali jednotlivá tlačítka, nebylo jich nikdy mnoho, ale i tak nám mohla v okně překážet. Ve složitějších aplikacích se místo většího počtu jednotlivých tlačítek používá menu (nabídkový pruh), což je vlastně úsporně řešená soustava tlačítek. Vyzkoušíme tvorbu menu u textového editoru s několika málo velmi zjednodušenými funkcemi.

Tvorba menu

K vytvoření menu slouží komponenta TMainMenu, kterou najdete v kategorii Standard. Podobně jako u komponenty Timer je jedno, kam ji na formulář umístíte, zobrazí se jen čtvereček a dále vytvořené menu je v projektu automaticky umístěno k hornímu okraji. Po dvojím kliknutí na umístěné komponentě se spustí Menu Designer (editor, návrhář) - viz obrázek. Stačí vybrat prázdné políčko (tlačítko) a v Object Inspectoru máte k dispozici známé vlastnosti a události jako u samostatných tlačítek. Hlavní a známé pro nás jsou vlastnost Caption a událost OnClick. Prázdná políčka automaticky přibývají ve vodorovném nebo svislém směru za poslední využité tlačítko, pokud byste chtěli umístit nabídku někam mezi stávající, máte na pravém tlačíku myši k dispozici nabídku Insert, která přidá tlačítko před vybrané.

Na obrázku jsou v nabídkách podtržená písmena, která slouží jako známé zkratkové klávesy s klávesou Alt (např. Alt+S), stačí v Caption připsat před vybrané písmeno znak & (ampersand).

Pokud chcete oddělit položky menu vodorovnou čarou (rozčlenit nabídku), stačí do Caption vepsat pomlčku.

Pro vytvoření dalšího podmenu v menu slouží na pravém tlačítku myši nabídka Create Submenu.

Ze solidnějších aplikací znáte také nabídku, kterou získáte po kliknutí pravým tlačítkem myši na objekt (komponentu), k jeho vytvoření slouží komponenta TPopupMenu. Pracuje se s ní obdobně jako s MainMenu, navíc je ale potřeba komponentě, ke které je určeno, do vlastnosti PopupMenu zapsat nebo vybrat název tohoto nového PopupMenu.

Další podrobnější popis a užitečné praktické poznámky pro tvorbu složitějších menu najdete v kurzu Umíme to s Delphi v 9.lekci.


Sebehezčí menu nemá smysl, pokud nepatří ke smysluplnému programu. Začneme pracovat na jednoduchém textovém editoru a postupně doplníme funkce nabídek v menu.

Začínáme tvořit textový editor

Pro náš textový minieditor k vytvořenému menu přidáme pro psaní textu komponentu TRichEdit z palety Win32. Tato komponenta pracuje s textem ve formátu RTF, umožňuje nastavit více vlastností než MEMO a navíc třeba jen vybrané části textu. Více vlastností využijeme v další lekci, případně můžete najít ve 13. lekci kurzu Umíme to s Delphi. Aby se RichEdit zvětšoval s případně se zvětšujícím oknem aplikace, nastavte mu vlastnost Anchor všude na True.

Tlačítka (nabídky) v menu (případně i popupmenu) ošetříme stejně jako běžná tlačítka - využijeme jejich událost OnClick.
Nejprve doplníme silně zjednodušenou funkci pro nabídku Soubor - Nový, vymažeme obsah RichEditu stejným způsobem jako u ListBoxu (zatím bez obvyklých uložení změn), tlačítko má v ukázce jméno Nový:
procedure TForm2.NovyClick(Sender: TObject);
begin
RichEdit1.Lines.Clear;
end;

Pro složitější ukázku doplníme funkci známou z Poznámkového bloku - Zalamování řádků, které se hodí u delších textů, abychom nemuseli posouvat text posuvníkem.
Nejprve je potřeba doplnit tlačítko Zalamování řádků do menu, nejspíše v nabídce Úpravy. Pro událost OnClick tohoto tlačítka využijeme následující proceduru (v ukázce má tlačítko Name - lamani):
procedure TEditor.lamaniClick(Sender: TObject);
begin
lamani.Checked:=not Lamani.Checked;
if lamani.Checked then
begin
RichEdit1.WordWrap:=true; //nastavit lámání řádek
RichEdit1.ScrollBars:=ssVertical; //zrušit horizontální posuvník
end
else
begin
RichEdit1.WordWrap:=false; //zrušit lámání řádek
RichEdit1.ScrollBars:=ssBoth; //přidat horizontální posuvník
end;
end;

V této proceduře je několik nám zatím neznámých věcí:
- Checked - je vlastnost tlačítka, která určuje, zda je zatrženo (fajfka) nebo ne, při zatržení má hodnotu True jinak False
- not - logická negace, v našem případě otáčí checked ze zapnuto na vypnuto a obráceně
- jestliže je "lámání" zatrženo, nastaví se vlastnost WordWrap RichEditu na True (řádky se budou zalamovat) a zruší se vodorovný posuvník (ScrollBars), protože nebude potřeba - jinak (není-li zatrženo "lámání") se zruší zalamování (WordWrap:=false) a přidá se vodorovný posuvník


Naše předcházející projekty končily okamžitě po kliknutí na tlačítko, takové ukončení textového editoru se stránkou textu by ale pro pisatele mohlo být dosti nepříjemné (:-) ). Často uživatel klikne na tlačítko pro ukončení ve chvíli, kdy si vzpomene, že zapomněl uložit, že chce něco doplnit, nebo prostě omylem. V našem textovém editoru ošetříme tlačítko Konec už lepším způsobem, zjednodušeným oproti tomu, který znáte z běžných aplikací - po kliknutí na tlačítko se aplikace zeptá, zda chce uživatel opravdu skončit, k tomu už nestačí jen Showmessage.

MessageDlg, MessageDlgPos

Funkce MessageDlg zobrazí box se zvolenými tlačítky a umožňuje reagovat na stisk každého z nich. Nejlepší bude uvést příklad, použitelný pro naše tlačítko (nabídku) Konec:
procedure TForm2.KonecClick(Sender: TObject);
begin
if MessageDlg('Opravdu konec?', mtConfirmation, [mbYes, mbNo], 0) = mrYes
then Close;
end;

O funkcích bude řeč později, zatím jen tolik, že funkce MessageDlg dává výsledek podle toho, na které tlačítko bylo kliknuto. V kulatých závorkách za MessageDlg jsou uvedené její parametry, oddělené čárkou. Význam parametrů je následující:
- první je řetězec, který chcete zobrazit ('Opravdu konec?')
- druhý parametr určuje účel dialogu a tím i obrázek, který se na boxu zobrazí. Možné hodnoty:
mtWarning – žlutočerná ikonka značící výstrahu,
mtError – červená „stopka“ značící chybu, všichni ji dobře známe :),
mtInformation – modré písmeno "i" značící informaci,
mtConfirmation – modrý otazník značící dotaz (žádost o potvrzení),
mtCustom – na boxu nebude standardně zhola nic
- dále je v hranatých závorkách uvedený seznam tlačítek, která se na boxu mají zobrazit, mohou to být: mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mnNoToAll, mbYesToAll, mbHelp (je možné použít některé z předdefinovaných konstant (např. mbOKCancel má stejný význam jako [mbOK, mbCancel])
- poslední je číslo „context ID“ tématu nápovědy, které se má objevit, stiskne-li uživatel F1 (nebo klikne na tlačítko Help) při otevřeném dialogu. Nechcete-li použít, nechte 0.

MessageDlg vrací hodnotu tlačítka, jehož stisknutím uživatel dialog opustil. Možné hodnoty v podstatě odpovídají příslušným tlačítkům (mb nahradí mr): mrNone, mrAbort, mrYes, mrOk, mrRetry, mrNo, mrCancel, mrIgnore, mrAll.

Uvedený příkaz pro tlačítko Konec zkontroluje, jestli bylo kliknuto na tlačítko Yes, potom se vykoná příkaz Close - ten zavře okno (máme-li jediné, ukončuje aplikaci jako Application.Terminate).

Funkce MessageDlgPos je vylepšením funkce MessageDlg o souřadnice levého horního rohu (poslední dvě čísla), na kterých se má box objevit, například:
MessageDlgPos('Opravdu konec?', mtConfirmation, [mbYes, mbNo], 0, 100,200)

Titulek okénka (boxu) bude pro obě funkce stejný jako název spustitelného souboru s aplikací (tedy název projektu v Delphi).


Funkce pro tlačítko Konec již byla sice mužsky stručným ale přece jen dialogem. Jenže například pro uložení nebo otevření souboru je potřeba složitější dialog - zapsat název, vybrat složku atd. Jejich naprogramování by bylo pracné, proto je v Delphi připravena celá paleta nejrůznějších dialogů, které můžeme využít. Jejich nevýhodou je, že je nemůžeme upravovat, mohou nastat také jazykové problémy, protože v podstatě využívají nainstalovanou verzi Windows, která může být anglická apod.

Standardní dialogy

Z palety dialogů využijeme dva nejpoužívanější - TOpenDialog a TSaveDialog, k jejich mnohým vlastnostem se vrátíme později (případně se můžete podívat do Umíme to s Delphi - 12.díl). V návrhu se po vložení objeví opět jen čtverečky (viz obrázek), u příslušných tlačítek (nabídek Soubor - Otevřít resp. Soubor - Uložit použijeme následující procedury:
procedure TForm2.openClick(Sender: TObject);
begin
if OpenDialog1.Execute then
RichEdit1.Lines.LoadFromFile(OpenDialog1.FileName);
end;

procedure TForm2.saveClick(Sender: TObject);
begin
if SaveDialog1.Execute then
RichEdit1.Lines.SaveToFile(SaveDialog1.FileName);
end;

V obou procedurách se využívá nejdůležitější metoda (funkce) všech dialogů Execute. Tato metoda vrací True, uzavřel-li uživatel dialog stiskem OK (a chce-li tedy výběr použít) a False, pokud dialog ukončil stiskem Cancel nebo stiskem křížku v rohu, apod. Druhou využitou vlastností těchto dialogů je FileName, co to asi bude?
Zatím jsou i tyto procedury s dialogy velmi zjednodušené, ale i tak fungují a můžete tedy napsaný text uložit i otevřít (příponu musíme připsat "ručně" - .txt nebo .rtf).

Aplikace ukládej do složky s názvem lekce15 .

Úkoly:

Základní úloha:

Vytvoř aplikaci podle textu lekce (viz ukázka ) - editor s nabídkami Soubor - Nový, Uložit, Otevřít, Úpravy - Zalamování řádků a Konec (ošetřený). Napište (nebo zkopírujte) text delší než jeden řádek a uložte (otevřete).


Úloha na plus:

Doplňte PopupMenu pro RichEdit s alespoň dvěma vybranými nabídkami ze základní úlohy.


Úlohy na jedničku:

Úlohu na plus doplňte o nabídku Nápověda, ve které bude jen položka O programu zobrazující verzi a autora programu (hlášku do dvou řádků, odřádkování provede znak #13).