Časovač
Časovač je nevizuálny komponent (počas behu programu ho nevidíme, ale prejavuje sa svojou činnosťou). Jeho úlohou je v pravidelných intervaloch generovať udalosť OnTimer. Niektoré zaujímavé vlastnosti časovača:
- Interval ... určuje čas v milesekundách medzi dvoma "tiknutiami" (udalosťami OnTimer)
- Enabled
časovač na palete s komponentmi.
Do formulára položíme komponenty:
- TTimer (nachádza sa medzi komponentmi na záložke System);
- TLabel
Pri udalosti časovača OnTimer sa zavolá funkcia Timer1Timer:
int Cas=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { Cas++; Label1->Caption=Cas; }
Môžeme používať aj viacero časovačov, pričom každý z nich "tiká" podľa svojich intervaloch.
int Cas=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { Cas++; Label1->Caption=IntToStr(Cas); }
int Cas2=0;
void __fastcall TForm1::Timer2Timer(TObject *Sender) { Cas2++; Label2->Caption=Cas2; }
void __fastcall TForm1::Button1Click(TObject *Sender) { Timer1->Enabled=!Timer1->Enabled; Timer2->Enabled=!Timer2->Enabled; }
Na prvý pohľad bežia oba časovače paralelne, v skutočnosti sa veľmi rýchlo strieda vykonávanie funkcií Timer1Timer a Timer2Timer.
Animácia
Do formulára vložíme komponent obrázok a časovač. Na vykresľovanie animácie vyžijeme grafickú plochu obrázka: TCanvas *g; g=Image1->Canvas; Časovaču treba nastaviť Interval na hodnotu 50. Čím je tento interval kratší, tým sa za sekundu nakreslí viac obrázkov, a preto bude animácie plynulejšia (nebude trhaná).
int y=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { g->Brush->Color=clWhite; g->FillRect(Image1->ClientRect); y=y+5; if (y>=Image1->Height) y=0; g->Brush->Color=clRed; g->Ellipse(100-10, y-10, 100+10, y+10); }
Rovnomerne zrýchlený pohyb:
float y=0, dy=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { g->Brush->Color=clWhite; g->FillRect(Image1->ClientRect); dy=dy+0.5; y=y+dy; if (y>Image1->Height-10) { y=Image1->Height-10; dy=-dy; } g->Brush->Color=clRed; g->Ellipse(100-10, y-10, 100+10, y+10); }
Ovládanie pomocou klávesnice
Šípkami na klávesnici budeme určovať smer pohybu štvorčeka. Využijeme udalosti formulára:
- OnKeyDown ... vzniká pri stlačení klávesu
- OnKeyUp ... vzniká pri pustení klávesu
Ukážka udalosti OnKeyDown (OnKeyUp funguje analogicky):
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { Caption=Key; }
V parametri Key je uložený kód práve stlačeného klávesu - celé 16-bitové číslo (typ WORD). Pri stláčaní klávesov mení nadpis formulára. Tak sa dajú zistiť kódy rôznych klávesov, napríklad, kláves šípka vľavo má kód 37 - namiesto čísel sa však ľahšie pamätá konštanta VKLEFT. Analogicky existujú konštanty VKRIGHT, VKUP, VKDOWN.
Udalosti klávesnice vznikajú iba vtedy, keď je okno našej aplikácie aktívne. Pozor: ak v aplikácii použijeme tlačidlá, editovacie políčka a podobné komponenty, ktoré reagujú na vstup z klávesnice, treba formuláru nastaviť vlastnosť KeyPreview na true a funkcie k udalostiam OnKeyDown a OnKeyUp programovať veľmi obozretne.
Ovládanie pohybu šípkami na klávesnici:
int x=0, y=0, dX=0, dY=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { g->Brush->Color=clWhite; g->FillRect(Image1->ClientRect); x=x+dX; y=y+dY; g->Brush->Color=clRed; g->Rectangle(x-10, y-10, x+10, y+10); }
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { if (Key==VK_LEFT) { dX=-5; Key=0; } else if (Key==VK_RIGHT) { dX=+5; Key=0; } else if (Key==VK_UP) { dY=-5; Key=0; } else if (Key==VK_DOWN) { dY=+5; Key=0; } }
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift) { if (Key==VKLEFT || Key==VKRIGHT) { dX=0; Key=0; } else if (Key==VKUP || Key==VKDOWN) { dY=0; Key=0; } }
Všimnime si, že do Key priraďujeme hodnotu 0. Tým povieme, že iné komponenty, ktoré s klávesnicou pracujú, už nemajú reagovať na stlačenie tohto klávesu (pozn.: parameter Key nie je vďaka symbolu & iba obyčajný parameter - bude o tom podrobnejšia prednáška).
Predchádzajúci program vyzerá na prvý pohľad komplikovane. Spôsobuje to viacnásobné vnáranie príkazu if ... else. Pritom chceme podľa hodnoty v premennej Key zvoliť iba jednu zo štyroch možných alternatív a vykonať pár príkazov na nastavenie smeru pohybu. Pre takéto situácie existuje v C++ príkaz switch - pomocou neho zapíšeme predchádzajúci program elegantne.
Najčastejšie používaná syntax príkazu:
switch (výraz) {
case hodnota1:
príkaz; ... príkaz; break;
case hodnota2:
príkaz; ... príkaz; break; ...
default:
príkaz; ... príkaz; }
Ako príkaz funguje:
- vyhodnotí sa výraz a podľa jeho hodnoty sa rozhodne, ktorá vetva case sa vykoná:
- ak sa hodnota výrazu nezhoduje so žiadnou hodnotou uvedenou za case, vykonajú sa príkazy za vyhradeným slovom default: (táto vetva je nepovinná - nemusíme ju písať)
- kľúčové slovo break ukončí vykonávanie príkazu switch. Keby sme break zabudli napísať, prípadne ho naschvál nenapísali, pokračovalo by sa vo vykonávaní príkazov aj z nasledujúcej vetvy case (prípadne default).
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift) { switch (Key) {
case VK_LEFT:
dX=-5; Key=0; break;
case VK_RIGHT:
dX=+5; Key=0; break;
case VK_UP:
dY=-5; Key=0; break;
case VK_DOWN:
dY=+5; Key=0; } }
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift) { switch (Key) {
case VK_LEFT:
case VK_RIGHT:
dX=0; Key=0; break;
case VK_UP:
case VK_DOWN:
dY=0; Key=0; } }
Animácia viacerých objektov
V prípade animovania viacerých objektov nepoužijeme pre každý objekt zvlášť časovať. Bolo veľmi neefektívne a objekty by sme ťažko synchronizovali. Preto používame iba jediný časovač a funkciu, ktorá obsluhuje udalosť OnTimer iba mierne modifikujeme:
- zmažeme grafickú plochu
- pohneme všetky objekty
- nakreslíme všetky objekty
class TVlocka {
private:
int X, Y;
public:
void Nastav(int nX, int nY); void Pohni(); void Kresli(); };
void TVlocka::Nastav(int nX, int nY) { X=nX; Y=nY; }
void TVlocka::Pohni() { if (random(4)==0) X=X+random(3)-1; Y=Y+2+random(2); if (Y>Form1->Image1->Height) Y=0; }
void TVlocka::Kresli() { g->Pixels[X][Y]=clWhite; }
const Max=1000; TVlocka v[Max]; int poc=0;
void __fastcall TForm1::Timer1Timer(TObject *Sender) { g->Brush->Color=clBlack; g->FillRect(Image1->ClientRect); g->Brush->Color=clRed; for (int i=0; i=Max) return; v[poc].Nastav(X, Y); poc++; }
void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (!Shift.Contains(ssLeft) || poc>=Max) return; v[poc].Nastav(X, Y); poc++; }