7.Prednaska
7. Prednáška |
Udalosti
Tento princíp sa používa v oknových grafických rozhraniach (GUI), napr. keď sa programuje vo Windows. Je to špeciálny spôsob riadenia programov, v ktorom aplikácia, formulár aj samotné komponenty môžu reagovať na nejaké podnety (väčšinou) z vonku. Hovoríme im udalosti a udalosťami riadené programovanie(po angl. event).
Každá udalosť má
- meno, napr. onClick, onCreate
- akciu, t.j. časť programu, ktorá sa vykoná pri vzniku udalosti;
- najčastejšie sa realizujú procedúrami, napr. Button1Click, FormCreate
- mená procedúr sa vytvárajú automaticky (mohli by sme ich aj zmeniť) v inšpektore objektov, pričom sa poskladá meno komponentu a meno udalosti
- akcie mávajú aj parametre (špecifický detail), ktorý nám niekedy upresní, za akých okolností sa udalosť udiala
Práca s myšou
V Lazaruse sa s myšou pracuje pomocou udalostí, ktoré automaticky vznikajú pri každom pohybe myši alebo klikaní do formulára. Túto udalosť dostáva ten komponent formulára, nad ktorým sa myš práve nachádza (napr. grafická plocha alebo tlačidlo). Procedúra, ktorá sa vyvolá ako reakcia na udalosť (event driver) pohybu alebo kliknutia myši, dostáva ako parametre aj súradnice myši (X, Y) - tieto sú vždy relatívne vzhľadom na ľavý horný roh komponentu - v grafickej ploche sú to normálne grafické súradnice bodu.
Klikanie
Začneme s udalosťou OnMouseDown, ktorá označuje, že myšou sme klikli niekde do grafickej plochy. Takže v Inšpektore objektov v záložke Udalosti nájdeme riadok OnMouseDown a potom sem dvojklikneme:
Otestujeme to programom, v ktorom kliknutie do grafickej plochy na tomto mieste nakreslí malý kruh a vypíše súradnice kliknutého bodu. Nesmieme zabudnúť vo FormCreate vymazať grafickú plochu:
Všimnite si, že procedúra Image1MouseDown má viac rôznych parametrov. Pre nás sú najdôležitejšie dva parametre X a Y, v ktorých dostávame súradnice kliknutého miesta v grafickej ploche.
Nasledujúci program ukáže, že kliknuté body môžeme veľmi jednoducho spájať čiarami (LineTo). V každom kliknutom bode nakreslíme aj malú kružnicu, aby bolo lepšie vidieť kliknuté miesto:
Ďalší program ukazuje spôsob, ako pracujeme s klikaním do štvorčekov štvorcovej siete. Procedúra FormCreate nakreslí prázdnu štvorcovú sieť. Potom každé kliknutie do plochy zistí, do ktorého štvorčeka sme klikli a ten potom vyfarbí modrou farbou. V programe sme definovali pomocnú globálnu procedúru Stvorcek, ktorá nakreslí štvorček v R-tom riadku a S-tom stĺpci štvorcovej siete. Globálna konštanta D má hodnotu veľkosti štvorčeka siete.
Pri kliknutí do plochy vypočítame riadok (Y div D) a stĺpec (X div D) štvorčeka siete a ten potom nakreslíme s modrou výplňou.
Pohyb myši
Ďalšou udalosťou pri práci s myšou v grafickej ploche je pohyb myši - vzniká vtedy, keď sa kurzor myši pohne nad grafickou plochou bez ohľadu na to, či je niektoré tlačidlo myši zatlačené alebo nie. V Inšpektore objektov v záložke Udalosti nájdeme riadok OnMouseMove a vytvoríme procedúru na spracovanie udalosti Image1MouseMove. Procedúra je podobná Image1MouseDown - tiež má dva parametre X a Y, ktoré sú momentálne súradnice myši nad plochou. V nasledujúcom programe prechádzame myšou nad grafickou plochou - nemusíme pritom zatláčať tlačidlá myši:
Procedúra Image1MouseMove má ešte jeden užitočný parameter: Shift. V ňom nám systém odovzdáva informáciu o stlačených tlačidlách myši. Tento parameter je množinového typu a s pascalovskými množinami zatiaľ pracovať nevieme. Tento parameter môže nadobúdať rôzne hodnoty, ale pre nás sú asi najzaujímavejšie tieto:
- Shift = [] // nezatlačili sme žiadne tlačidlo
- Shift = [ssLeft] // zatlačili sme len ľavé tlačidlo
- Shift = [ssRight] // zatlačili sme len pravé tlačidlo
- Shift = [ssLeft, ssRight] // zatlačili sme naraz obe tlačidlá
Ak chceme opraviť náš program, aby kreslil iba pri stlačenom ľavom tlačidle, zapíšeme podmienku takto:
Po spustení vidíme, že krúžky sa kreslia len pri stlačenom ľavom tlačidle myši.
Ďalší program spája body na pozícii myši s nejakým dopredu zvoleným bodom (napr. 150, 150):
V mnohých aplikáciách, kde je dôležité poznať súradnice polohy myši, sa do Image1MouseMove pridáva výpis súradníc X a Y. Môžeme napr. pri pohybe myši vypisovať X a Y do titulku formulára (hoci by sme aj mohli niekde do formulára vložiť komponent jednoduchý text (TLabel) a súradnice myši vypisovať sem):
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin Caption := Format('[%d, %d]', [X, Y]); ... end;
Súradnice myši sa teraz budú vypisovať vždy, bez ohľadu na to, čo robí program.
Ťahanie
Môžeme využiť obe udalosti od myši v jednom programe. Budeme rozlišovať kliknutie a ťahanie, pričom pri kliknutí (udalosť onMouseDown) sa niečo nastaví a pri ťahaní (udalosť onMouseMove) sa to využije. Príklad ukáže kreslenie krivky: kliknutie sem prenesie pozíciu pera (MoveTo) a ťahanie už kreslí čiary (LineTo):
Pri každom kliknutí môžeme nastaviť aj hrúbku alebo farbu kreslených čiar, napr. náhodné farby a hrúbky:
Pri kliknutí (onMouseDown) si môžeme v globálnych premenných napr. X1, Y1 zapamätať súradnice tohto kliknutého miesta a pri ťahaní myši (onMouseMove) môžeme túto súradnicu využiť. Napríklad nakreslíme rôznofarebné vejáre:
V ďalšom programe budeme kresliť kruhy tak, že kliknutie určí stred kruhu a ťahanie určuje bod na kružnici. Aby sme mohli takúto kružnicu nakresliť, musíme vypočítať jej polomer (vzdialenosť bodu na kružnici od jej stredu).
Nasledujúci príklad ilustruje iné využitie výpočtu vzdialenosti dvoch bodov. Počas ťahania chceme kresliť náhrdelníky zložené z kruhov s polomerom napr. 20. Ak by sme pri ťahaní (onMouseMove) kreslili takéto kruhy, mohli by byť príliš nahusto a prekrývali by sa. Preto pre každý bod zistíme, či už je dostatočne vzdialený od predchádzajúceho (vzdialenosť aspoň 40) a ak áno, tak ho nakreslíme:
Predtým sme už klikali do políčok štvorcovej siete a zafarbovali sme ich. Podobnú ideu použijeme aj v nasledujúcom programe. Pri ťahaní myšou sa budú zafarbovať krúžky, ktoré sú vo vnútri štvorcovej siete. Kliknutie nastaví náhodnú farbu.
Konštanta D označuje veľkosť štvorčeka siete, teda priemer krúžku.
Komponent posuvná lišta
Posuvná lišta (posúvač) je vizuálny komponent, na ktorom sa nachádza bežec. Tento môžeme počas behu projektu posúvať a program si vie pritom zistiť polohu tohto bežca. My budeme používať komponent TrackBar, ale úplne rovnako by sme mohli použiť aj komponent ScrollBar. Bežca môžeme posúvať aj tak, že keď je tento komponent aktívny, stláčame klávesy šípok.
Pre komponent posuvná lišta TrackBar (vyberieme ho z palety komponentov Common Controls a uložíme do formulára) sú dôležité tieto nastavenia (vlastnosti, property) a vlastnosti (nastavujeme ich v inšpektore objektov):
- nastavenia Min a Max vyjadrujú minimálnu a maximálnu dosiahnuteľnú hodnotu pre posúvač, t.j. keď bude bežec úplne naľavo (resp. dolu pre zvislý posúvač), posúvač má hodnotu Min, keď bude bežec úplne napravo (resp. dolu), má hodnotu Max;
- nastavenie Position je momentálna pozície bežca (zrejme vždy je to hodnota z intervalu Min .. Max);
- udalosť onChange bude automaticky volaná vždy, keď používateľ posúva bežca na lište
- onChange procedúra sa automaticky pripraví dvojklikom na tento komponent vo formulári
- posuvnú lištu môžeme otočiť tak, aby bola zvislo - nastavíme jej vlastnosť Orientation na trVertical
Použitie posuvnej lišty ukážeme na niekoľkých príkladoch. Prvý príklad vypisuje hodnotu posúvača pri každom jeho posunutí. Do formulára položíme grafickú plochu Image1 a posuvnú lištu TrackBar1. V inšpektore objektov mu nastavíme napr. tieto hodnoty:
- Min = 0
- Max = 1000
Dvojklikneme na komponent posúvača a vytvorí sa procedúra:
procedure TForm1.TrackBar1Change(Sender: TObject); begin Image1.Canvas.FillRect(ClientRect); Image1.Canvas.Font.Height := 100; Image1.Canvas.TextOut(10, 10, IntToStr(TrackBar1.Position)); end; |
![]() |
Momentálnu pozíciu bežca sme zistili ako TrackBar1.Position a vypísali sme ju veľkým písmom.
V druhom príklade budeme kresliť štvorcovú špirálu: začneme s úsečkou dĺžky 1 a ťahať ju budeme, napr. na sever (Y znížime o 1), pokračujeme úsečkou dĺžky 2 smerom na východ (X zvýšime o 2), ďalšia úsečka smerom na juh má dĺžku 3 (Y zvýšime o 3), ďalšia smerom na západ s dĺžkou 4 (X znížime o 4), ... Každá ďalšia úsečka je o 1 dlhšia a postupne sa striedajú ich smery. Počet takto kreslených úsečiek nech je daný momentálnou pozíciou bežca posuvnej lišty: robot pomocou for-cyklu nakreslí štvorcovú špirálu, pričom počet opakovaní určí posúvač. Minimum nastavíme na 0 a maximum, napr. na 400:
Keď je bežec posuvnej lišty úplne vľavo (Position vtedy dáva hodnotu 0), cyklus nenakreslí nič. Procedúra len zmaže grafickú plochu.
Všimnite si sériu vnorených if - then - else, v ktorých sa stále vyhodnocuje rovnaký výraz I mod 4 a testuje sa na rôzne hodnoty. V Pascale to vieme zapísať aj čitateľnejšie ďalším príkazom vetvenia - príkazom case. Jeho všeobecná syntax je:
case ordinálny výraz of konštanta1: príkaz1; konštanta2: príkaz2; konštanta3: príkaz3; ... end; |
alebo
case ordinálny výraz of konštanta1: príkaz1; konštanta2: príkaz2; konštanta3: príkaz3; ... else príkazy end; |
Tento case-príkaz funguje takto:
- vyhodnotí výraz za case
- medzi konštantami konštanta1, konštanta2, konštanta3, ... nájde vypočítanú hodnotu a vykoná príslušný príkaz
- ak sa nenájde vypočítaná hodnota a case-príkaz nemá else-vetvu, príkaz končí bez toho, aby niečo vykonal,
- ak sa nenájde vypočítaná hodnota a existuje else-vetva, vykonajú sa všetky príkazy za else.
Musí platiť, že
- výraz aj všetky konštanty musia byť rovnakého ordinálneho typu,
- jednotlivé vetvy prípadov označujeme len konštantami - nesmú to byť premenné ani výrazy,
- vo vetve sa nemusí vykonať len jeden príkaz, ale keď potrebujeme, aj viac - vtedy ich musíme uzavrieť medzi begin a end,
- vo vetve môžeme uviesť aj viac konštánt - vtedy ich navzájom oddelíme čiarkou,
- pred else-vetvou musíme písať bodkočiarku.
Predchádzajúce riešenie prepíšeme pomocou case-príkazu:
Ďalší príklad ukáže použitie posuvnej lišty na zmenu farby. Pre TrackBar1 nastavíme Min=0 a Max=255. Pozícia bežca bude teda číslo z intervalu <0, 255> a budeme ním meniť červenú zložku RGB:
procedure TForm1.TrackBar1Change(Sender: TObject); begin Image1.Canvas.Brush.Color := RgbToColor(TrackBar1.Position, 0, 0); Image1.Canvas.FillRect(ClientRect); end; |
![]() |
Môžete sledovať, že posúvaním bežca sa plynulo mení odtieň červenej. Pridáme ďalšie dva komponenty posuvná lišta a obom nastavíme rovnaké Min=0 a Max=255. Využijeme ich na nastavovanie zelenej a modrej zložky RGB. Do programu pre TrackBar1Change dopíšeme zistenie pozícií aj pre TrackBar2 aj TrackBar2. Mohli by sme teraz zadefinovať úplne rovnaké procedúry TrackBar2Change a TrackBar3Change (dvojklikom na príslušné komponenty a kopírovaním obsahu z TrackBar1Change). My to urobíme lepšie:
- v Inšpektore objektov pre TrackBar2 nájdeme udalosť onChange, ale neurobíme dvojklik na zatieľ voľné políčko v tomto riadku,
- namiesto toho klikneme na malú šípku a zo zoznamu ponúkaných hodnôt vyberieme TrackBar1Change,
- tým sme Lazarusu oznámili, že nebudeme definovať novú procedúru pre udalosť onChange komponentu TrackBar2, ale použije sa už existujúca procedúra TrackBar1Change,
- to isté urobíme aj pre tretí posúvač TrackBar3
Program teraz vyzerá takto:
procedure TForm1.TrackBar1Change(Sender: TObject); begin Image1.Canvas.Brush.Color := RgbToColor(TrackBar1.Position, TrackBar2.Position, TrackBar3.Position); Image1.Canvas.FillRect(ClientRect); end; |
![]() |
Táto procedúra je pre všetky tri udalosti spoločná.
Časovač
Časovač je nevizuálny komponent a teda po spustení aplikácie nebude zobrazený. Časovač si môžeme predstaviť ako hodiny, ktoré s nejakou frekvenciou "tikajú" a pri každom tiknutí môžu vykonať nejakú akciu, t.j. vyvolať udalosť (spustiť nejakú procedúru). Frekvenciu "tikania" nastavíme v inšpektore objektov ako vlastnosť Interval. Túto hodnotu môžeme hocikedy počas behu programu meniť. Pozastavenie, resp. naštartovanie časovača môžeme zmeniť pomocou vlastnosti Enabled, pre ktoré True znamená, že hodiny bežia a False znamená, že sme ich pozastavili.
Časovač má pre nás jedinú zaujímavú udalosť onTimer, ktorá sa naštartuje po uplynutí "tikacieho" intervalu. Zodpovedá jej procedúra Timer1Timer.
Vytvorme takúto jednoduchú aplikáciu: do formulára okrem grafickej plochy Image1 vložíme aj komponent časovač Timer1, ktorý sa nachádza v systémovej palete komponentov (System). Vo formulári sa objaví ikona komponentu Timer, ktorú ale počas behu programu nebude vidieť:
Teraz môžeme nastavovať vlastnosti pre časovač v inšpektore objektov, napr. zmeníme frekvenciu "tikania": nastavenie Interval na hodnotu 50 bude znamenať 50 milisekúnd, t.j. frekvencia časovača bude 20-krát za sekundu:
Po dvojkliknutí na ikonu časovača Timer1 vo formulári sa automaticky vytvorí prázdna procedúra pre udalosť onTimer, t.j. akcia, ktorá sa vyvolá pri každom "tiknutí". Ako prvý príklad sem môžeme zapísať kreslenie náhodných čiar:
procedure TForm1.FormCreate(Sender: TObject);
begin
Image1.Canvas.FillRect(Image1.ClientRect);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Image1.Canvas.LineTo(Random(Image1.Width), Random(Image1.Height));
end;
Tento program kreslí náhodné čiary rýchlosťou, ktorú sme nastavili vo vlastnosti Interval.
Pri práci s časovačom si musíme uvedomiť, že jeho procedúra Timer1Timer bude automaticky volaná systémom, pričom vždy sa najprv vytvoria všetky lokálne premenné (ak sú v tejto procedúre nejaké deklarované), potom sa vykoná telo procedúry a na koniec sa všetky lokálne premenné zrušia. Z tohto dôvodu si v lokálnych premenných nemôžeme uchovávať údaje, ktoré by sa zišli aj pri ďalších volaniach udalosti časovača. Ďalší príklad ukazuje, ako si v globálnej premennej uchovávame hodnotu, ktorú využijeme v časovači ako X-ovú súradnicu a po každom tiknutí ju aj meníme:
var
X: Integer;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Image1.Canvas.FillRect(Image1.ClientRect);
Image1.Canvas.Font.Height := 100;
Image1.Canvas.TextOut(X, 50, 'Pascal');
X := X + 5;
if X > Image1.Width then
X := 0;
end;
Tento program pomaly posúva nejaký text zľava doprava, pričom, keď vypadne z grafickej plochy, objaví sa na ľavej strane a pokračuje v svojom pohybe. Na zmenu rýchlosti pohybu textu môžeme experimentovať menením frekvencie: do formulára vložíme komponent posuvná lišta (TrackBar1) a nastavíme jej udalosť onChange (dvojklikneme na komponent vo formulári):
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
Timer1.Interval := TrackBar1.Position * 10;
end;
Pre posuvnú lištu môžete nastaviť Min = 0 a Max = 20. Všimnite si teraz, že ak pre časovač nastavíte Interval na 0, časovač zastane.
Ďalší príklad ilustruje spôsob vykresľovania ručičkových hodín. Ukážme pohyb sekundovej ručičky:
Na ďalšom príklade ilustrujeme zastavovanie časovača. Vytvoríme aplikáciu, v ktorej budeme vedieť naštartovať a zastavovať stopky. Do formulára namiesto grafickej plochy vložíme jednoduchý text (Label1), ktorému nastavíme nejaké zväčšené písmo. Tiež sem pridáme dve tlačidlá: prvé (Button1) na naštartovanie, resp. zastavenie stopiek; druhé (Button2) na vynulovanie počítadla. Vlastnosť Interval pre časovač bude nastavená na 1000, t.j. 1 sekundová frekvencia. Časovač by mal byť hneď pri štarte zastavený, napr. vlastnosť Enabled nastavte na False (môžeme to urobiť aj vo FormCreate).
V ďalšom príklade sa na kliknutie myšou do grafickej plochy (Image1) naštartuje kreslenie 50 sústredných rôznofarebných štvorcov. Každé "tiknutie" časovača nakreslí jeden zo štvorcov a zmenší veľkosť nasledovného štvorca (globálna premenná A). Keď sa nakreslí posledný štvorec a premenná A nadobudne hodnotu 0, časovač sa zastaví. Interval pre časovač nastavte napr. na hodnotu 30.
Všimnite si, že ak sa štvorce ešte nedokreslili a klikneme do plochy, tieto štvorce sa už nedokreslia a začnú sa kresliť na novej pozícii. Ak by sme tomuto chceli zabrániť, t.j. požadujeme, aby sa počkalo, kým sa štvorce nedokreslia, môžeme do Image1MouseDown pridať kontrolu, či časovač ešte beží (v procedúre sme tieto dva riadky zakomentovali).
Táto istá úloha sa dá riešiť aj tak, že časovač necháme bežať stále, aj počas toho, keď sa žiadne štvorce nekreslia. Počas behu časovača sme nechali vypisovať (do titulku aplikácie) počítadlo - t.j. globálnu premennú N, aby bolo vidieť, že časovač naozaj stále beží:
var SX, SY, A, N: Integer; procedure TForm1.FormCreate(Sender: TObject); begin Image1.Canvas.FillRect(Image1.ClientRect); Timer1.Enabled := True; end; procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin //if A > 0 then // Exit; SX := X; SY := Y; A := 50; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Inc(N); Caption := IntToStr(N); if A > 0 then begin Image1.Canvas.Pen.Color := Random(256 * 256 * 256); Image1.Canvas.Rectangle(SX - A, SY - A, SX + A, SY + A); Dec(A); end; end;
Ťahanie myšou a časovač
Časovač môžeme využiť aj počas ťahania myšou. Príklad ukazuje, čo môže spôsobiť, ak sa počas kreslenia myšou náhodne mení hrúbka pera. Interval časovača môžeme nastaviť na 100.
V ďalšom príklade sa pri ťahaní myšou štartuje rast farebných úsečiek. Interval pre časovač môže byť napr. 10.