Každý objekt, vygenerovaný prostředím Delphi, má kromě vlastností (property) ještě definované události (events) a metody (methods). Ve struktuře definování objektu představují vlastnosti hodnoty jednotlivých proměnných, definovaných pro objekt, nebo zděděných od jeho předchůdců. Ty z nich, které jsou přístupné již před spuštěním programu, si můžeme přednastavit pomocí Object Inspectoru, jiné jsou dostupné pouze za běhu programu (run-time only), některé jsou dokonce přístupné jen pro čtení. Naproti tomu metody a události představují procedury. Metoda je procedura, kterou manipulujeme s daným objektem (měníme jeho vlastnosti a podobně). Událost je procedura, která se vyvolá v případě, že dojde k nějaké akci, která má dopad na daný objekt. Obsloužením událostí (dopsáním výkonného kódu programu) tedy definujeme, co má daný objekt provést, když k dané události dojde. Typické události jdou různé podle objektů. U tlačitka je to například jeho stisknutí myší (OnClick), u textu (Label) to může být například klik (OnClick) nebo dvojitý klik (OnDblClick), u komponenty Edit buď změna obsahu (OnChange), kliknutí a podobně, u formuláře například změna jeho velikosti (OnResize). Obsluhu dané události zapíšeme tak, že v Object Inspectoru zvolíme záložku Events, vybereme příslušnou řádku, a dvojklikem do ní vygenerujeme proceduru pro příslušnou obsluhu, kam stačí již jen dopsat obslužný kód.
Někdy se stává, že nechceme, aby programn provedl všechno
ihned, ale pracoval postupně, v oddělených časových
okamžicích. Příkladmem může být vykreslení některých
typů grafů, kdy může být zajímavé, jakou rychlostí
přibývá jaká část grafu; dalším typickým případem jsou
animace. Občas se také stává, že potřebujeme, aby program
vždy po nějakém čase například zkontroloval obsah
adresáře na serveru, zda nedošla nová pošta. Všechny tyto
akce nám pomůže provádět komponenta Timer , kterou nalezneme na liště System.
Jako první si zkusíme program, který bude pravidelně zvyšovat hodnotu, zobrazovanou komponentou Label1, o jedničku. Vezmeme prázdný formulář, umístíme na něm komponenty Label a Timer; u komponenty Label1 nastavíme hodnotu Caption na nulu (číslice "nula", 0). Zkusíme dvojklik na Timer, a do obsluhy napíšeme ono zvětšení o jedničku:
Label1.Caption:= IntToStr(StrToInt(Label1.Caption)+1);
Nastavíme property Interval u Timer1 na nějaké rozumné číslo (číslo je v milisekundách, takže zkuste například 333) a zkontrolujeme, zda je hodnota property Enabled nastavena na True (True - povoleno, False - zakázáno).
Poznámka 1. Proměnná, která nabývá hodnot (jen a pouze) True a False (dvoustavová) se nazývá logická. Logickou proměnnou označujeme v Pascalu jako Boolean, zpravidla psáno s velkým počátečním písmenem, například
var b : Boolean;
Poznámka 2. Pokud se nestačí obsluha činnosti, vyvolané událostí OnTimer u příslušného timeru obsloužit, a mezitím nastane tato událost znovu, tak tato druhá již obsluhu nevyvolá. Pokud tedy zvolíte interval příliš krátký, mohou se jednotlivé události ztrácet.
Poznámka 3. Samotná komponenta Timer se na formuláři za běhu programu nezobrazuje. Podobných komponent potkáme ještě více. Mohou být proto umístěny přes nějakou jinou komponentu.
Napište program, který počítá od nějakého rozumného čísla k nule. Úloha je příliš jednoduchá (jen se změní znaménko a počáteční hodnota Label1.Caption. Jiný problém je, že by se program měl ukončit tak, aby po dopočtení k nule skončil.
Za logický výraz považujeme takový, jehož výsledkem je jedna z hodnot logické proměnné (True - False). V logickém výraze se nejčastěji vyskytne porovnání - hodnoty dvou výrazů (proměnných, proměnné a konstanty, či jiné kombinace) se porovnají pomocí tzv. operátorů. Několik z nich si uvedeme:
a < b | a je menší než b |
a > b | a je větší než b |
a <= b | a je menší nebo rovno b. Pokud se použijí dvě znaménka, nesmí mezi nimi samozřejmě být žádná mezera. |
a >= b | a je větší nebo rovno b. Všimněte si prosím, že operátory jsou v tom pořadí, jak je čteme (nezaměňovat!) |
a = b | a rovná se b. Jedno z míst, kde se v Pascalu vyskytuje samotné rovnítko. |
a <> b | a nerovná se b, přesněji je různé od b. |
Složitější podmínky můžeme sestavit pomocí logických operátorů.
and | nabývá hodnoty True, pokud oba operandy mají hodnotu True |
or | nabývá hodnoty True, pokud alespoň jeden z operandů nabývá hodnoty True |
xor | nabývá hodnoty True, pokud hodnoty operandů jsou různé |
not | unární operátor, obrací hodnotu operandu napravo od sebe (jako záporné znaménko) |
Katastrofou je, že v Pascalu se tytéž operátory nechají použít pro operace s celočíselnými proměnnými (které si pro tento případ představujeme v podobě binárního zápisu jejich hodnoty). Důsledkem je nepříjemná priorita operací v Pascalu:
Pokud se vyhodnocuje výraz, postupuje se mezi operacemi se stejnou prioritou zleva doprava, přičemž priority jsou následující:
závorky | nejprve se vždy vyhodnotí výraz v závorkách |
unární operace | not, záporné znaménko u čísla; výpočet hodnoty funkcí (s parametrem v závorce) |
násobení | * / mod div and |
sčítání | + - (ve funkci sčítání dvou čísel) or xor |
porovnání | < > <= >= <> = |
Výčet obsahuje jen dosud probrané operátory. Důsledkem je, že pokud napíšete
a < b + 9
, vyhodnotí se výraz tak, že se nejprve spočte hodnota b + 9, a ta se porovná s a, což je zřejmě to, co autor výrazu chtěl. Pokud ovšem napíšeme
a>3 and a<7
je tento výraz řešen tak, že se nejprve vypočte hodnota výrazu 3 and a (pro celá čísla dokonce proveditelné), a pak dosazením vznikne nesmysl (výraz se dvěma porovnáními). Správný zápis výrazu tedy je
(a>3) and (a<7)
Závorek není nikdy dost. Pokud napíšete nějaké závorky navíc, překladač Pascalu je bude ignorovat, nemají tedy vliv na rychlost výsledného programu či kvalitu překladu.
Podmíněný příkaz v Pascalu má následující tvar:
if podmínka then příkaz else příkaz;
Část počínaje else je nepovinná. My si nejprve ukážeme tento zkrácený tvar
if podmínka then příkaz;
a zapamatujeme si, že část s else je částí příkazu, a před else tedy není středník.
Náš program tedy bude mít ve výsledku následující tvar:
Form1.Label1.Caption:= IntToStr(StrToInt(Label1.Caption)-1); if StrToInt(Label1.Caption) = 0 then Form1.Close;
Pro demonstrační příklad se nejlépe hodí hodnoty, udávající polohu objektu na formuláři. V následujícím textu předpokládám, že na formuláři je jen tlačítko (komponenta Timer se nezobrazuje). Property Left tlačítka určuje, jak je daleko od levého okraje funkční plochy formuláře (tzv. Client area).
Button1.Left := Button1.Left + 1;
Pokud zkusíte takovouto obsluhu události Timer1.OnTimer, pak se tlačítko bude pomalu (alespoň při nastavení Timer1.Interval na 333) pohybovat vpravo. Pokud ovšem narazí na pravý okraj formuláře, formulář si sám vygeneruje scrollbar (posuvník) a tlačítko sice neopustí formulář, ale opustí právě zobrazovanou plochu. Aby se to nestalo, musíme stále hlídat několik parametrů prostředí, ve kterém se pohybuje. Jsou to následující property:
Form1.ClientWidth | šířka plochy formuláře, schopné zobrazit jiný prvek |
Form1.Button1.Width | šířka samotného tlačítka |
Form1.Button1.Left | pozice tlačítka na ploše formuláře |
Tyto property musí při pohybu vpravo stále zachovávat následující vztah:
Button1.Left + Button1.Width < Form1.ClientWidth
Při pohybu vlevo naopak nesmí Button1.Left být menší než nula.
Při skutečné realizaci ovšem zpravidla nechceme, aby tlačítko doběhlo až na úplný okraj okna. Proto se před porovnáním od Form1.ClientWidth odečítá nějaké číslo. Krok posuvu tlačítka také nebývá jeden bod, spíše 3 až 5. Tlačítko neběží od levého okraje, ale od nějaké vzdálenosti (jako napravo). Aby bylo možné tohle všechno zrealizovat, musíme vytvořit alespoň jednu globální proměnnou, ve které bude alespoň směr pohybu (logická proměnná). Pokud tato proměnná bude nadeklarována příkazem (šedivé části představují původní kód):
var Form1: TForm1; smer : Boolean; implementation
, pak by obsluha události od časovače mohla vypadat například následovně:
if Button1.Left + Button1.Width > Form1.ClientWidth - 8 {je překročena pravá mez} then smer := False; {True = doprava} if Button1.Left < 8 {je překročena levá mez} then smer := True; if smer then Button1.Left := Button1.Left + 3 else Button1.Left := Button1.Left - 3;
Komponenta Checkbox představuje zaškrtávací políčko. Její zaškrtnutí vyjadřuje property Checked, která nabývá logických hodnot a můžeme si ji zaškrtnout jak před během programu nastavením této hodnoty v Object inspectoru, tak po spuštění zaškrtnutí myší. Může nám tedy v předchozím případě nahradit globální proměnnou smer. Přidejte si proto na formulář komponentu CheckBox1 a upravte program následujícím způsobem:
if Button1.Left + Button1.Width > ClientWidth - 8 {je překročena pravá mez} then CheckBox1.Checked := False; {True = doprava} if Button1.Left < 8 {je překročena levá mez} then CheckBox1.Checked := True; if CheckBox1.Checked then Button1.Left := Button1.Left + 3 else Button1.Left := Button1.Left - 3;
A opět vystačíme zcela bez proměnných. Pokud nesmažete deklaraci proměnné smer, nic se nestane; paměti je v dnešních PC již dostatek. Takže zbývá zatím jen úloha na samostatné procvičení. Přidejte dva Edit boxy tak, aby bylo možné property Interval u komponenty Timer1, a také krok posuvu tlačítka za běhu programu měnit.
Program je v přiloženém souboru.