7.Prednaska

Z Pascal
Prejsť na: navigácia, hľadanie
7. Prednáška

úlohy | cvičenie


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:

v inšpektore prejdeme na záložku Udalosti nájdeme riadok onMouseDown 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:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.Ellipse(X - 4, Y - 4, X + 4, Y + 4);
  Image1.Canvas.TextOut(X, Y, Format('[%d, %d]', [X, Y]));
end;

klikanie do plochy

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:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.LineTo(X, Y);
  Image1.Canvas.Ellipse(X - 2, Y - 2, X + 2, Y + 2);
end;

spájanie kliknutých bodov

Ď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.

const
  D = 50;
 
procedure Stvorcek(R, S: Integer);
begin
  Form1.Image1.Canvas.Rectangle(S * D, R * D, S * D + D + 1, R * D + D + 1);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
var
  I, J: Integer;
begin
  for I := 0 to Image1.Height div D do
    for J := 0 to Image1.Width div D do
      Stvorcek(I, J);
  Image1.Canvas.Brush.Color := clBlue;
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Stvorcek(Y div D, X div D);
end;

klikanie do štvorcovej 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:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  Image1.Canvas.Ellipse(X - 5, Y - 5, X + 5, Y + 5);
end;

200px link=http://pascal.input.sk/images/9/97/P7.x.png

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:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Shift = [ssLeft] then
    Image1.Canvas.Ellipse(X - 5, Y - 5, X + 5, Y + 5);
end;

200px link=http://pascal.input.sk/images/9/97/P7.x.png

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):

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Shift = [ssLeft] then
  begin
    Image1.Canvas.Line(150, 150, X, Y);
  end;
end;

{{{3}}}

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):

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.MoveTo(X, Y);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Shift = [ssLeft] then
    Image1.Canvas.LineTo(X, Y);
end;

kreslenie rukou do grafickej plochy

Pri každom kliknutí môžeme nastaviť aj hrúbku alebo farbu kreslených čiar, napr. náhodné farby a hrúbky:

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.MoveTo(X, Y);
  Image1.Canvas.Pen.Color := Random(256 * 256 * 256);
  Image1.Canvas.Pen.Width := Random(20) + 1;
end;

kreslenie s náhodnou zmenou 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:

var
  X1, Y1: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  X1 := X;
  Y1 := Y;
  Image1.Canvas.Pen.Color := Random(256 * 256 * 256);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Shift = [ssLeft] then
    Image1.Canvas.Line(X1, Y1, X, Y);
end;

farebné 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).

var
  X1, Y1: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  X1 := X;
  Y1 := Y;
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  R: Integer;
begin
  if Shift = [ssLeft] then
  begin
    R := Round(Sqrt(Sqr(X - X1) + Sqr(Y - Y1)));
    Image1.Canvas.Ellipse(X1 - R, Y1 - R, X1 + R, Y1 + R);
  end;
end;

kreslenie kruhu ťahaním

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:

var
  X1, Y1: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  X1 := X;
  Y1 := Y;
  Image1.Canvas.Brush.Color := Random(256 * 256 * 256);
  Image1.Canvas.Ellipse(X - 10, Y - 10, X + 10, Y + 10);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if (Shift = [ssLeft]) and (Sqrt(Sqr(X - X1) + Sqr(Y - Y1)) >= 20) then
  begin
    Image1.Canvas.Ellipse(X - 10, Y - 10, X + 10, Y + 10);
    X1 := X;
    Y1 := Y;
  end;
end;

kreslenie kruhov nie príliš husto

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.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.Brush.Color := Random(256 * 256 * 256);
  Image1.Canvas.Pen.Color := Image1.Canvas.Brush.Color;
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
const
  D = 15;
 
  procedure Kruh(R, S: Integer);  // riadok a stĺpec siete
  begin
    Image1.Canvas.Ellipse(D * S, D * R, D * S + D, D * R + D);
  end;
 
begin
  if Shift = [ssLeft] then
    Kruh(Y div D, X div D);
end;

kruhy v štvorcovej sieti

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;

zobrazenie hodnoty posúvača

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:

procedure TForm1.TrackBar1Change(Sender: TObject);
var
  I, X, Y: Integer;
begin
  Image1.Canvas.FillRect(ClientRect);
  X := Image1.Width div 2;
  Y := Image1.Height div 2;
  Image1.Canvas.MoveTo(X, Y);
  for I := 1 to TrackBar1.Position do
  begin
    if I mod 4 = 1 then
      Dec(Y, I)
    else if I mod 4 = 2 then
      Inc(X, I)
    else if I mod 4 = 3 then
      Inc(Y, I)
    else if I mod 4 = 0 then
      Dec(X, I);
    Image1.Canvas.LineTo(X, Y);
  end;
end;

štvorcová špirála

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:

procedure TForm1.TrackBar1Change(Sender: TObject);
var
  I, X, Y: Integer;
begin
  Image1.Canvas.FillRect(ClientRect);
  X := Image1.Width div 2;
  Y := Image1.Height div 2;
  Image1.Canvas.MoveTo(X, Y);
  for I := 1 to TrackBar1.Position do
  begin
    case I mod 4 of
      1: Dec(Y, 2 * I);
      2: Inc(X, 3 * I);
      3: Inc(Y, 2 * I);
      else Dec(X, 3 * I);
    end
    Image1.Canvas.LineTo(X, Y);
  end;
end;

štvorcová špirála

Ď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;

zmena RGB farby

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;

zmena RGB farby

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ť:

komponent časovača vo formulári

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:

nastavenie frekvencie časovača

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:

var
  Uhol: Integer;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
  Image1.Canvas.Ellipse(150 - 90, 100 - 90, 150 + 90, 100 + 90);
  Image1.Canvas.Line(150, 100, 150+Round(80*Sin(Uhol/180*Pi)), 100-Round(80*Cos(Uhol/180*Pi)));
  Uhol := Uhol + 6;
end;

sekundová ručička

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).

var
  Sekundy: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Sekundy := 0;
  Label1.Caption := '0';
  Timer1.Enabled := False;   // časovač môže byť zastavený aj takto
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Sekundy := Sekundy + 1;
  Label1.Caption := IntToStr(Sekundy);
end;
 
procedure TForm1.Button1Click(Sender: TObject);    // Štart/Stop
begin
  Timer1.Enabled := not Timer1.Enabled;
end;
 
procedure TForm1.Button2Click(Sender: TObject);    // Reštart
begin
  Sekundy := 0;
  Label1.Caption := '0';
  Timer1.Enabled := True;
end;

stopky

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.

var
  SX, SY, A: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
  Timer1.Enabled := False;
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  //if Timer1.Enabled then
  //  Exit;
  SX := X;
  SY := Y;
  A := 50;
  Timer1.Enabled := True;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  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
  else
    Timer1.Enabled := False;
end;

farebné štvorce

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.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.MoveTo(X, Y);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Shift = [ssLeft] then
    Image1.Canvas.LineTo(X, Y);
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if Random(5) = 0 then
    Image1.Canvas.Pen.Width := Random(10) + 1;
end;

náhodná zmena hrúbky pera

V ďalšom príklade sa pri ťahaní myšou štartuje rast farebných úsečiek. Interval pre časovač môže byť napr. 10.

var
  X1, Y1, D: Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Canvas.FillRect(Image1.ClientRect);
  Image1.Canvas.Pen.Width := 5;
end;
 
procedure TForm1.Image1MouseDown(Sender: TObject; Button:
      TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  Image1.Canvas.Pen.Color := Random(256 * 256 * 256);
end;
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
       X, Y: Integer);
begin
  if (Shift = [ssLeft]) and (D = 0) then    // ak ešte nič nerastie
  begin
    X1 := X;
    Y1 := Y;
    D := 5;
  end;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if D > 0 then    // ak má niečo rásť
  begin
    Image1.Canvas.Line(X1, Y1, X1, Y1 - D);
    D := D + 5;
    if D > 40 then    // ak je už dostatočne dlhá
      D := 0;    // ukonči rast
  end;
end;

rastúce paličky pri ťahaní myšou



späť | ďalej