A je tu další díl kurzu o programování v Delphi. V minulém díle jsme probrali pár základních komponent a dneska se vrhneme na další! Ale nebudeme programovat náš MP3 přehrávač, dneska začneme dělat druhý projekt: textový editor.
Zajímá vás, co jsem si pro vás přichystal na dnešní díl? Pro dnešek můžete zapomenout na náš MP3 přehrávač. Budeme totiž dělat textový editor, který nás bude, společně s přehrávačem, provázet dále během kurzu.
Návrh uživatelského prostředí
Seznam komponent:
Komponenta | Název (name) | Další atributy |
Formulář | form1 | Caption: Textový editor |
Formulář | form2 | Caption: O aplikaci BorderStyle: bsDialog |
Memo | memo | Align: alClient WordWrap: false |
OpenDialog | OpenDialog1 | Title: Otevřít soubor... |
SaveDialog | SaveDialog1 | Title: Uložit soubor… |
MainMenu | MainMenu1 | následující tabulka |
Caption (popiska) | Menu | Další atributy |
Soubor | žádné | – |
Úpravy | žádné | – |
Nápověda | žádné | – |
Nový | Soubor | Shortcut: Ctrl+N |
Otevřít | Soubor | Shortcut: Ctrl+O |
Uložit | Soubor | Shortcut: Ctrl+S |
Konec | Soubor | – |
Zalamování řádek | Úpravy | Name: zalamovani |
O Aplikaci | Nápověda | – |
A teď si projdeme jednotlivé komponenty:
Formulář
Určitě jste si všimli, že dnes budeme mít v projektu dva formuláře. Delphi umožňují mít v aplikaci i více formulářů (dokonce je lze generovat i za běhu, stejně jako jsme to dělali s komponentami v minulém díle). Formuláře jsou vlastně takové komponenty. Mají mnoho vlastností a událostí, ze kterých si dnes ukážeme pouze vlastnost BorderStyle, která nastavuje typ ohraničení okna plikace:
- bsDialog – okno se bude chovat jako dialog, má pouze tlačítko zavřít, bez možnosti minimalizace, změny rozměrů
- bsNone – okno nebude mít žádné ohraničení ani titulkový pruh (vhodné pro fullscreen aplikace)
- bsSingle – okno vypadá standardně, akorát nelze měnit jeho rozměry
- bsSizeable – standardní okno včetně možnosti změny rozměrů
- bsSizeToolWin – okno lze minimalizovat (ale ne přes tlačítko na titulkovém pruhu) a zavřít, můžete měnit jeho velikost, akorát titulkový pruh je zmenšený (jako např. u okna Object TreeView
- bsToolWin – stejné jako v předchozím případě, pouze bez možnosti měnit rozměry okna
K dalším vlastnostem formuláře se dostaneme zase někdy jindy. Jen pro úplnost, nový formulář se do apliakce přidává přes File → New → Form a ukládá se do samostatného souboru (.PAS).
Memo
Memo je komponenta pro vstup textu ve formátu TXT, tedy bez formátování. Komponentu Memo určitě důvěrně znáte, je to prakticky totéž, do čeho píšete v Poznámkovém bloku ve Windows. Pokud do něj chcete nahrát data z textového soubru, slouží k tomu funkce LoadFromFile(nazev_souboru: string), pro uložení dat je zase funkce SaveToFile(nazev_souboru: string). Obě funkce najdete v jeho třídě Lines. Celý text je dostupný v atributu Text, který se opět nachází v Lines. Pokud chcete přidávat postupně řádky, slouží k tomu funkce (opět se nachází v Lines) Add(text: string), která přidá daný text vždy na novou řádku.
OpenDialog
Jak je z názvu patrné, jedná se o dialog otevření. Na formuláři je reprezentován pouze jako ikonka. Za běhu jej vyvoláte funkcí Execute, která vrací true, pokud byl dialog ukončen tlačítkem Otevřít, a false, pokud byl uzavřen jinak.
Cesta a název otevřeného souboru je poté dostupný v atributu FileName, pokud je dostupná volba více souborů zároveň, jsou soubory v poli Files.
Detailní nastavení lze provést v atributu Options v Object Inspectoru.
SaveDialog
Dialog pro uložení. Více ho nebudu rozpitvávat, pracuje se s ním stejně jako s OpenDialogem.
MainMenu
Komponenta hlavní nabídky. Pokud jste přesně nepochopili můj popis v tabulce, měly by vám pomoci následující obrázky:
|
|
Už je to jasné? Sloupec Menu v tabulce udává, do kterého menu dané položka patří. Pokud je tam uvedeno žádné, znamená to, že se jedná o hlavní menu. Položky se do menu přidávají tak, že klikete na ten prázný rámeček, v Object Inspectoru zadáte Caption a stiskenete Enter. Pokud jako Caption napíšte – (pomlčka), vytvoří se oddělovač.
Programujeme!
Tak jdeme na to! Nejprve si musíme nadeklarovat pár globálních proměnných:
- upraveno typu boolean s výchozí hodnotou false
- ulozeno typu boolean s výchozí hodnotou false
První proměnná udává, jestli byly od posledního uložení provedeny změny, druhá jestli už byl soubor někdy uložen.
Dále si vytvoříme vlastní funkci Uloz s parametrem dotaz typu boolean. Ten udává, jestli se před uložením máme zeptat na uložení změn, nebo pouze vyvolat dialog o uložení. Funkce vrací true, pokud byl soubor uložen, a false, pokud ne.
function Uloz(dotaz: boolean): boolean;
begin
result:=false; //pokud by funkce neočekávaně skončila, vrátí se FALSE
with Form1 do begin //protože funkce není ve třídě TForm, musíme ji volat ručně
if dotaz then begin //pokud se má aplikace zeptat na uložení...
case MessageDlg('Přejete si uložit změny?',mtConfirmation,[mbYes,mbNo,mbCancel],0) of //vyvolá se dialog s dotazem
mrNo: begin //talčítko NE:
result:=true; //funkce se zdařila
exit; //ukočnit funkci
end;
mrCancel: begin //talčítko Cancel
result:=false; //funkce se nezdařila
exit; //ukončit funkci
end;
end;
end;
if not ulozeno then begin //pokud soubor nikdy ješte nebyl uložen
if SaveDialog1.Execute then begin //vyvolá dialog a pokud ten byl uzavren přes Uložit
memo.Lines.SaveToFile(SaveDialog1.Filename); ///tak uloží obsah mema
ulozeno:=true; //a nastaví potřebné proměnné
upraveno:=false;
result:=true;
exit;
end;
end else begin //pokud už někdy předtím uložen byl
memo.Lines.SaveToFile(SaveDialog1.FileName); //tak jenom uložíme data bez vyvolání dialogu
upraveno:=false; //a nastavíme proměnné
result:=true;
end;
end;
end;
Komentáře mluví za vše, ale pro jistotu: tato funkce slouží k uložení souboru. Zohledňuje při tom, jestli si přejeme vyvolat dotaz o uložení (to určuje její parametr dotaz). V případě, že už byl soubor někdy předtím uložen, tak jenom znovu uloží data; pokud ještě uložený nebyl, zobrazí dialog a umožní uživateli zvolit název souboru.
Teď už to musí být jasné, takže jdeme dál…
Toto je procedura vyvolaná událostí onClick u položky menu Nový:
if upraveno then //pokud byl soubor od posledního uložení změněn, případně pokud ještě nebyl uložen
if not uloz(true) then exit; {vyvoláme funkci Ulož s parametrem TRUE, aby se zobrazil
dialog s dotazem, jestli si uživatel přeje změny uložit.
Pokud uživatel dá Cancel, vrátí funkce false a pak se
tato procedura ukončí. Pokud dá Ano nebo Ne, provedou se
ve funkci příslušné akce a funkce vrátí true. V tom
případě bude tato procedura pokračovat....}
memo.Clear; //nejprve se odstraní všechny data z Memo
ulozeno:=false; //a vyresetují se proměnné
upraveno:=false;
O funcki této procedury se rozepisovat nebudu, komentáře jsou dost jasné.
Nyní vytvoříme proceduru události onClick položky menu Otevřít:
if OpenDialog1.Execute then begin //pokud byl dialog ukončen tlačítkem Otevřít
Nov1Click(Sender); {zavoláme proceduru standardně obsluhující událost onclick
u položky menu Nový. Ta se postará o příslušné vyvolání dialogu,
o uložení a o vyčištění Mema, abychom to zbytečně nemuseli
programovat znovu }
memo.Lines.LoadFromFile(OpenDialog1.FileName); //načteme daný soubor
upraveno:=false; //a nastavíme proměnnou
end;
Zde se pozastavím u toho druhého řádku, tedy volání procedury Nov1click. Proces otevření souboru se vlastně skládá ze dvou částí. První je vytvoření nového dokumentu. Její programové zpracování by tedy bylo stejné jako u procedury Nov1Click. No a když už jsme ji jednou udělali, tak proč to dělat znovu, že? :) Druhá část je pak samoté otevření souboru, to už je primitivní záležitost.
Dále nás čeká obsluha události onClick u položky Konec
: if upraveno then //pokud byl soubor upraven...
if not uloz(true) then exit; //tak se ještě zeptáme, jestli ho chce uživatel před ukončením uložit
if MessageDlg('Opravdu si přejete skončit?',mtConfirmation,[mbYes,mbNo],0)=mrYes then
Form1.close;
//pak se ještě radši zeptáme, jestli chce uživatel opravdu skončit. Pokud ano, tak přikazem
close zavřeme hlavní formulář, čímž ukončíme program.
Další v pořadí je obsluha onClick u položky Uložit:
Uloz(false); //tohle ani komentář nepotřebuje
onClick u položky Zalamování řádek obsloužíme takto:
zalamovani.Checked:=not zalamovani.Checked; //pokud je položka menu zaškrtnuta, tak ji odškrteneme a naopak
memo.WordWrap:=zalamovani.Checked; //nastaví vlastnost zalamování řádek v Memu
if zalamovani.Checked then //pokud je zalamování aktivní...
memo.ScrollBars:=ssVertical //...tak nám stačí pouze vertikální posuvník
else //jinak..
memo.ScrollBars:=ssBoth; //...zobrazíme oba
A nakonec ještě poslední položka O Aplikaci:
form2.ShowModal; //otevře modálně druhý formulář (formulář O Aplikaci)
Tady kousek odbočím od našeho textového editoru a vrátim se k formulářům. Formláře totiž lze otevřít dvěma způsoby: modálně a nemodálně. Modálně se formulář otevírá procedurou ShowModal. Takto otevřený formulář je zobrazený nad všemi ostatními okny v aplikaci a nelze jej minimalizovat, ani se nelze překliknou do jiného okna (typické pro dialogy). Zároveň také po otevření okna modálním způsobem se procedura, která jej otevřela, zastaví a dokud není modální okno zase zavřeno, tak stojí. Poté se zase rozeběhne a pokračuje dál. U nemodálního formuláře je tomu přesně naopak. Je na stejné úrovni jako osatní okna v aplikaci a procedura, která jej zavolala, v klidu běží dál, bez ohledu na to, jestli je fomrulář otevřený nebo zavřený.
A ještě jsem zapoměl na obsluhu poslední události. Tou je událost onChange komponenty Memo:
if not upraveno then upraveno:=true;
Ta se volá vždy, když se v Memu něco změní, respektive když se změní jeho obsah.
A jsme zase na konci!
Pokud program zkompilujeme, mělo by vše fungovat přesně tak, jak jsme si řekli na začátku. Pokud ne, vraťte se nahoru a projděte článek znovu, jestli jste na něco nezapoměli.
Příšte nás čeká zase náš MP3 přehrávač, tentokrát bych to viděl na vytváření playlistu.
Úkol
A ani dnes vás nenechám zavřít tento článek, aniž bych vám nezadal nějaký úkol.
Tentokrát vytvoříte program, kde bude hlavní menu a Memo. V hlavním menu budou položky, kterými bude možné ovládat různá nastavení mema (obash, styl písma apod.). Text samozřejmě půjde uložit přes SaveDialog a zase otevřít přes OpenDialog…