29.10.2002
|
Myš
- pri práci s Pixels v grafickej
ploche sme trochu experimentovali aj s myšou: pri
pohyboch myšou nad grafickou plochou Image2 sme
zobrazovali príslušné bodky obrázka
- využili sme udalosť onMouseMove, ktorá
do obslužnej procedúry Image2MouseMove
posiela aj súradnice myši v parametroch X
a Y
- naučíme sa, ako sa pracuje s myšou -
grafická plocha má 3 rôzne udalosti:
- onMouseDown - zatlačili sme nad plochou
niektoré tlačidlo myši
- onMouseMove - myš sa hýbe
nad plochou
- onMouseUp - pustili sme tlačidlo
myši
- začneme najjednoduchším prípadom:
vo formulári máme grafickú
plochu Image1 a priradíme jej udalosť onMouseMove
(dvojklikneme na riadok s onMouseMove v záložke
Events pre Image1 v Inšpektore objektov):
pohyb myši kreslí bodky:
|
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
Image1.Canvas.Pixels[X,Y]:=clBlack;
end;
|
- pohybom myši na plochou sa na príslušných
miestach zobrazujú bodky
- už sme si možno zvykli, že veľmi často,
keď robíme s grafikou a táto bliká,
treba do FormCreate pridať riadok:
aby grafická plocha neblikala:
|
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=true;
end;
|
- kreslením bodiek sa veľmi ťažko niečo
naozaj nakreslí, preto sa môžeme
pokúsiť namiesto bodky (Pixels) kresliť
čiary (LineTo):
pohyb myši spája čiary:
|
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
Image1.Canvas.LineTo(X,Y);
end;
|
- teraz sa naozaj spájajú
čiary podľa pohybu myši, lenže čiary sa kreslia
aj keď sa tlačidlo myši nezatlačí
- využijeme parameter Shift: je typu TShiftState
a pre tento platí
type
TShiftState = set of
(ssShift,ssAlt,ssCtrl,ssLeft,ssRight,ssMiddle,ssDouble);
- v tomto parametri sa môžeme dozvedieť
či sú zatlačené tlačidlá na myši
alebo niektoré špeciálne klávesy
na klávesnici
- využijeme to na to, že čiary sa kresliť
len, ak je zatlačené ľavé tlačidlo
myši
kreslí sa len pri zatlačenom tlačidle
myši:
|
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
if Shift=[ssLeft] then
Image1.Canvas.LineTo(X,Y);
end;
|
- ešte stále to nie je správne
riešenie - po zatlačení tlačidla by sa
grafické pero malo posunúť do
štartového bodu kreslenia, ale bez spojenia
s predchádzajúcim bodom - využijeme
udalosť onMouseDown, v ktorej sa nastavíme
do štartového bodu pomocou MoveTo
pridáme začiatok kreslenej čiary:
|
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Shift=[ssLeft] then
Image1.Canvas.MoveTo(X,Y);
end;
|
- toto riešenie môže niekedy robiť problémy
(vyskúšajte počas kreslenia zatlačiť
kláves Ctrl), preto môžeme
použiť pomocnú logickú premennú
dole, ktorá označuje, či práve
kreslíme (či sme začali kresliť) a ďalej
sa už nepozerá na parameter Shift
použitie pomocnej premennej
|
var
dole:boolean = false;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
dole:=Shift=[ssLeft]; // alebo dole:=ssLeft in Shift;
if dole then Image1.Canvas.MoveTo(X,Y);
end;
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
if dole then Image1.Canvas.LineTo(X,Y);
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
dole:=false;
end;
|
- v situácii, keď nepotrebujeme pri
zatlačení tlačidla myši (onMouseDown)
nič nastavovať, stačí použiť len onMouseMove
kreslenie machúľ:
|
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
var
r:integer;
begin
if Shift=[ssLeft] then
with Image1.Canvas do begin
r:=random(5)+10;
Pen.Color:=random(16777216); // RGB(0,0,random(156)+100);
Brush.Color:=Pen.Color;
Ellipse(X-r,Y-r,X+r,Y+r);
end;
end;
|
- v procedúre pre udalosť onMouseMove
môžeme na nejaké miesto vo formulári
vypisovať momentálnu pozíciu myši:
- niekam do formulára umiestnime nový
komponent Label - text vo formulári
- keď budeme meniť jeho stavovú
premennú (property) Caption, bude
sa meniť jeho zobrazenie
kontrolné výpisy počas pohybu
myši nad grafickou plochou:
|
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
Label1.Caption:=IntToStr(X)+','+IntToStr(Y);
...
end;
|
Skicár - kresliaca aplikácia
ďalej ukážeme postupnú
konštrukciu jednoduchej kresliacej aplikácie:
- do formulára vložíme grafickú
plochu (Image1), pod ňu textový informačný
riadok (Label1), nad plochu tlačidlo s textom
zmaž (Button1)
prvá verzia programu:
|
var
dole:boolean = false;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=true;
Button1.Click; // zmaže sa grafická plocha
Label1.Caption:='';
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
with Image1, Canvas do begin
Brush.Color:=clWhite;
Brush.Style:=bsSolid;
FillRect(ClientRect);
end;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
dole:=ssLeft in Shift;
if dole then Image1.Canvas.MoveTo(X,Y);
end;
procedure TForm1.Image1MouseMove(Sender:TObject; Shift:TShiftState; X,Y:Integer);
begin
Label1.Caption:=IntToStr(X)+' '+IntToStr(Y);
if dole then Image1.Canvas.LineTo(X,Y);
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
dole:=false;
end;
|
Paleta farieb
- druhým krokom bude pridanie farebnej
palety, aby sme mohli zvoliť farbu kreslenia:
- nad grafickú plochu najprv položíme
menšiu grafickú plochu Image2,
ktorá bude obsahovať nejaký
obrázok palety (ak použijete bitmapu
paleta.bmp,
zvoľte veľkosť Image2 225x33) - umiestnite
ju napr. úplne vpravo
- pred Image2 položte malú plôšku
Image3, napr. veľkosti 25x25 - sem
sa bude vykresľovať aktuálna zvolená
farba - pri štarte programu čierna
kliknutím do Image2 sa zvolí
farba kresliaceho pera: nastaví sa farba
pera pre Image1 a tiež sa zafarbí
Image3:
spracovanie vybranej farby pera:
|
procedure TForm1.Image2MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Image1.Canvas.Pen.Color:=Image2.Canvas.Pixels[X,Y];
with Image3, Canvas do begin
Brush.Color:=Image1.Canvas.Pen.Color;
FillRect(ClientRect);
end;
end;
|
- asi by bolo dobré, keby bolo Image3
zafarbené už pri štarte programu: do
FormCreate pridáme jeho zafarbenie
inicializácia zobrazenia aktuálnej
farby:
|
procedure TForm1.FormCreate(Sender: TObject);
begin
...
with Image3, Canvas do begin
Brush.Color:=Image1.Canvas.Pen.Color;
FillRect(ClientRect);
end;
end;
|
Posúvač - posuvná lišta
spracovanie nastavovania hrúbky pera:
|
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
Image1.Canvas.Pen.Width:=TrackBar1.Position;
end;
|
Tlačidlá nástrojov kreslenia
- každý aj najjednoduchší kresliaci
program umožňuje kresliť rôznymi nástrojmi
- napr. nielen od ruky perom, ale aj úsečky,
obdĺžniky, elipsy ale aj vypĺňať farbou nejaké
oblasti
- na to zadefinujeme 5 malých tlačidiel
- komponentov SpeedButton - tieto majú
na rozdiel od klasického Button
viac vylepšení:
- keď na ne klikneme, môžu ostať
zatlačené (vyjadruje zvolený
nástroj)
- okrem textu môžu obsahovať obrázok
(môžete poexperimentovať s Glyph)
- môžeme ich zoskupiť do skupiny,
v ktorej iba jedno tlačidlo bude zatlačené
(zatlačenie iného spôsobí
automatické vyskočenie predchádzajúceho)
- do stavovej premennej (property) GroupIndex
všetkým nastavíme rovnaké
číslo, napr. 1
- na tlačidlá napíšeme texty
(je vhodné zvoliť nejaký malý
font): pero, úsečka, obdĺžnik, elipsa,
vyplň
- prvému tlačidlu (s textom pero) nastavíme
stavovú premennú Down
na true - tlačidlo bude zatlačené
- zadefinujeme globálnu premennú
rezim, ktorá bude obsahovať momentálne
zvolený nástroj - táto
premenná sa bude nastavovať v udalosti
onClick pre všetky SpeedButton1, SpeedButton2,
...
napr.
|
var
rezim:(pero,usecka,obdlznik,elipsa,vypln) = pero;
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
rezim:=pero;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
rezim:=usecka;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
rezim:=obdlznik;
end;
...
|
- asi by bolo krajšie, keby sme nemuseli
vytvárať pre každé tlačidlo zvlášť
procedúru (v inej aplikácii by
ich mohlo byť oveľa viac) - ale napísali
jednu univerzálnu - napr. SpeedButton1Click
by mohla byť spoločná pre všetky
- potom, ako ju zadefinujeme, ju nastavíme
všetkým ostatným tlačidlám
nástrojov: v záložke udalosti
(Events) inšpektora objektov pre SpeedButton2
sa nastavíme na riadok s udalosťou onClick
a z ponuky vyberieme SpeedButton1Click
- toto urobíme pre všetky tlačidlá
nástrojov (ak sme stihli vytvoriť SpeedButton2Click,
... - zrušíme ich tak, že vyprázdnime
telo procedúr a po uložení - Save
unitu sa korektne zrušia celé procedúry)
- SpeedButton1Click teraz na základe
parametra Sender zistí, ktorý
komponent ju zavolal a na základe toho
nastaví premennú rezim
univerzálna SpeedButton1Click procedúra:
|
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
if Sender = SpeedButton1 then
rezim:=pero
else if Sender = SpeedButton2 then
rezim:=usecka
else if Sender = SpeedButton3 then
rezim:=obdlznik
else if Sender = SpeedButton4 then
rezim:=elipsa
else if Sender = SpeedButton5 then
rezim:=vypln;
end;
|
- skôr ako sa pustíme do upravovania
procedúr Image1MouseDown a Image1MouseMove,
aby zvládali nové nástroje,
musíme vysvetliť ako budú pracovať:
- úsečka, obdĺžnik
a elipsa budú pracovať na veľmi podobnom princípe
- pri štarte nástroja (teda zatlačení
myšou) sa zapamätá momentálny
stav grafickej plochy v pomocnej bitmape
bmp (globálna premenná
typu TBitmap) a pre každom ťahaní
nástroja, napr. úsečky, sa
najprv grafická plocha vráti
do tohoto pôvodného stavu a
potom sa nakreslí nová úsečka
- musíme si pri tom pamätať
počiatočný bod kreslenia, napr. v
globálnych premenných x0
a y0
- pomocná premenná bmp
sa musí inicializovať v FormCreate
- režim vypĺňania oblasti je ešte jednoduchší
- celý sa zrealizuje pri zatlačení
tlačidla myši, t.j. v Image1MouseDown (mohol
by byť v Image1MouseUp - premyslite si,
čo by sa tým zmenilo) - na vypĺňanie
oblasti použijeme metódu FloodFill
spracovanie všetkých režimov:
|
var
dole:boolean = false;
rezim:(pero,usecka,obdlznik,elipsa,vypln) = pero;
bmp:TBitmap;
x0,y0:integer;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=true;
Button1.Click; // zmaže sa grafická plocha
Label1.Caption:='';
with Image3, Canvas do begin
Brush.Color:=Image1.Canvas.Pen.Color;
FillRect(ClientRect);
end;
bmp:=TBitmap.Create;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
dole:=ssLeft in Shift;
if dole then
with Image1.Canvas do
case rezim of
pero:
MoveTo(X,Y);
usecka,obdlznik,elipsa:
begin
bmp.Assign(Image1.Picture);
x0:=X; y0:=Y;
end;
vypln:
begin
Brush.Color:=Pen.Color;
FloodFill(X,Y,Pixels[X,Y],fsSurface);
end;
end;
end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
X,Y: Integer);
begin
Label1.Caption:=IntToStr(X)+' '+IntToStr(Y);
if dole then
with Image1.Canvas do
case rezim of
pero:
LineTo(X,Y);
usecka:
begin
Draw(0,0,bmp);
MoveTo(x0,y0); LineTo(X,Y);
end;
obdlznik:
begin
Draw(0,0,bmp);
Brush.Color:=Pen.Color;
Brush.Style:=bsClear;
Rectangle(x0,y0,X,Y);
end;
elipsa:
begin
Draw(0,0,bmp);
Brush.Color:=Pen.Color;
Brush.Style:=bsClear;
Ellipse(x0,y0,X,Y);
end;
end;
end;
|
Zaškrtávacie políčko
- ešte urobíme posledné vylepšenie:
umožníme používateľovi programu
aby si mohol zvoliť, či obdĺžnik, resp. elipsa
budú pri vykreslení vyplnené
farbou (zatiaľ sme ich vyrobili "deravé"
- nastavili sme Brush.Style:=bsClear;)
- do formulára vložíme ešte
jeden komponent - zaškrtávacie políčko
CheckBox - nastavíme mu popis
(Caption) napr. na plný a opravíme
v metóde Image1MouseMove kreslenie
obdĺžnika a elipsy
použitie CheckBoxu:
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState;
X,Y: Integer);
begin
...
obdlznik:
begin
Draw(0,0,bmp);
Brush.Color:=Pen.Color;
if CheckBox1.Checked then
Brush.Style:=bsSolid
else
Brush.Style:=bsClear;
Rectangle(x0,y0,X,Y);
end;
elipsa:
begin
Draw(0,0,bmp);
Brush.Color:=Pen.Color;
if CheckBox1.Checked then
Brush.Style:=bsSolid
else
Brush.Style:=bsClear;
Ellipse(x0,y0,X,Y);
end;
end;
end;
|
Zhrnutie
- stavové premenné komponentov (vidíme ich v inšpektore objektov) sú
podobné položkám záznamu (record)
- pri ich zmene v inšpektore objektov sa automaticky prejaví aj ich vizuálna
zmena vo formulári (napr. šírka, text, bublinkový help a pod.)
- v Delphi sa takýto typ stavových premenných nazýva Vlastnosť, t.j.
Property
- niektoré sú pre nás užitočné už počas tvorby formulára (Caption, Name, Hint,
Min, Max, ...), iné využijeme hlavne za behu programu (niektoré fungujú len za
behu, a preto v inšpektore objektov nie sú)
- meno komponentu (Name) treba zmeniť hneď ako sa položí do formulára
(ak ho chceme meniť), inak niektoré situácie Delphi nemusia správne uhádnuť a
opraviť túto zmenu korektne
- niektoré užitočné vlastnosti (property) nám známych komponentov:
- formulár TForm
- Caption - reťazec - titulok okna
- ClientWidth, ClientHeight - veľkosť vnútra okna (nie obvodu okna, pre ten je
veľkosť Width a Height)
- Left, Top - x-ová a y-ová súradnica okna na obrazovke - môžeme celé okno
posúvať
- Visible - či je okno viditeľné
- WindowState - okno môžeme zminimalizovať, zmaximalizovať
- Canvas (funguje len počas behu programu) - šedá plocha - môžeme do nej
kresliť (v udalosti OnPaint)
- tlačidlo TButton
- Caption - text na tlačidle
- Font - rovnako ako v grafickej ploche
- Height, Width - veľkosť
- Left, Top - poloha vo formulári
- Visible - môžeme ho skryť
- Hint, ShowHint - string a boolean - bublinkový help a či sa má zobrazovať
- Enabled - môžeme ho zablokovať, false znamená, že tlačidlo bude zašedené
- vlastnosti Width, Height, Left, Top, Visible, Hint, ShowHint, Enabled -
fungujú skoro rovnako pre skoro všetky typy komponentov
- grafická plocha TImage
- Canvas (funguje len počas behu programu) - sprístupnenie kreslenia do
grafickej plochy
- ClientRect (funguje len počas behu programu) - hodnota typu TRect, t.j.
obdĺžnik, ktorý popisuje veľkosť plochy
- malé tlačidlo TSpeedButton - veľmi podobné obyčajnému tlačidlu, ale
tieto tlačidlá môžu tvoriť skupinu (vzájomne sa vylučujú - maximálne jedno z
nich je zatlačené), môže mať aj obrázok
- Caption - text na tlačidle (môže byť spolu s obrázkom)
- GroupIndex - poradové číslo skupiny tlačidiel, ktoré sa navzájom vylučujú
- Down - či je zatlačené
- Glyph - obrázok
- posuvná lišta TTrackBar
- Min, Max - minimálna a maximálna hodnota
- Position - momentálna hodnota
- Orientation - (trHorizontal,trVertical)
- zaškrtávacie políčko TCheckBox
- Caption - text za políčkom
- Font - písmo pre text
- Checked - či je zaškrtnuté
- text TLabel
- Caption - ak reťazec obsahuje #13#10, bude viacriadkový
- Font - písmo pre text
- textová plocha TMemo
- Color - farba podkladu
- Font - písmo
- Lines - obsah textovej plochy - pole reťazcov
- ReadOnly - či má používateľ zakázané meniť obsah
- editovací riadok TEdit - je veľmi podobný TMemo
- Color - farba podkladu
- Font - písmo
- Text - momentálny obsah riadka
- ReadOnly - či má používateľ zakázané meniť obsah
- PasswordChar - ak obsahuje napr. '*', tak sa namiesto zadávaných
znakov budú vypisovať hviezdičky - používa sa pri zadávaní hesla
- udalosti (Events) = záložka v inšpektore objektov = môžeme definovať
správanie pri špecifických situáciách
- inšpektor nám pomôže správne zadeklarovať takú procedúru, ktorú vyvolá
Windows, keď vznikne príslušná udalosť (napr. klikne sa, zmení sa, hýbe sa a
pod.)
- tieto procedúry definujeme tak, že v záložke Events (v riadku) pri danej
udalosti dvojklikneme v pravom stĺpci (alebo si zvolíme procedúru
z už existujúcej ponuky procedúr)
- nedopisujte manuálne žiadne nové procedúry na spracovávanie udalostí - vždy
použite inšpektor objektov
- ak potrebujete nejakú procedúru obsluhujúcu udalosť zrušiť, najlepšie to
urobíte tak, že vyčistíte obsah procedúry - necháte v nej len počiatočný
begin a koncový end a pri nasledujúcom uložení
na disk (napr. Ctrl+S) ju Delphi automaticky vyhodí
Myš a korytnačky
- korytnačka je grafické pero, ktoré
dokáže nejaké veci navyše: jednoducho "vie
natočiť súradnicovú sústavu",
v grafickej ploche ich môžeme definovať
ľubovoľný počet, ...
- prvý príklad ilustruje použitie
korytnačky ako obyčajného grafického
pera
kreslenie korytnačkou:
|
var
k:TKor;
procedure TForm1.FormCreate(Sender: TObject);
begin
k:=TKor.Create; k.PH;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
k.PD;
end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
k.ZmenXY(X,Y);
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
k.PH;
end;
|
- v tomto programe je korytnačka "prilepená"
k myši - pri každom pohybe myši (onMouseMove)
sa pohne na jej miesto - korytnačka má
ale stále pero hore a kreslí len,
keď príde udalosť onMouseDown
- keď stlačíme nejaké tlačidlo
myši
- do onMouseMove môžeme pridať aj
iné akcie, napr. korytnačka sa najprv
otočí smerom k novej pozícii (použili
sme funkciu Smerom(x,y) - vypočíta
absolútny uhol k zadanému bodu
v rovine) a až potom sa na ňu presunie - pritom
môže niečo korytnačie kresliť
pri pohybe korytnačka kreslí úsečky:
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
k.Smer:=k.Smerom(X,Y);
k.PresunXY(X,Y);
k.Dopredu(100);
k.Dopredu(-100);
end;
|
môžeme pridať zmaz:
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
zmaz;
k.Smer:=k.Smerom(X,Y);
k.PresunXY(X,Y);
k.Dopredu(100);
k.Dopredu(-100);
end;
|
alebo
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
i:integer;
begin
k.Smer:=k.Smerom(X,Y);
k.PresunXY(X,Y);
for i:=1 to 5 do begin
k.Dopredu(10); k.Vpravo(144);
end;
end;
|
alebo farebné paličky:
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
k.Smer:=k.Smerom(X,Y)-90;
k.PresunXY(X,Y);
k.HP:=5; k.FP:=random(256*256*256);
k.Dopredu(30);
k.HP:=15; k.Dopredu(0); k.HP:=5;
k.Dopredu(-60); k.Dopredu(30);
end;
|
alebo rovnostranný trojuholník:
|
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
zmaz;
k.Smer:=k.Smerom(X,Y);
k.PresunXY(X,Y);
k.HP:=5; k.FP:=clGreen;
k.Vpravo(90); k.Dopredu(8); k.Vlavo(105); k.Dopredu(30.9);
k.Vlavo(150); k.Dopredu(30.9); k.Vlavo(105); k.Dopredu(8);
end;
|
- ďalší príklad ukáže
generovanie korytnačiek pri klikaní myšou:
kliknutie na voľné miesto vygeneruje
novú korytnačku, kliknutie na už existujúcu
korytnačku ju mierne otočí
klikanie na korytnačky:
|
var
k:array[1..100] of TKor;
n:integer = 0; // aktuálny počet korytnačiek
procedure TForm1.FormCreate(Sender: TObject);
begin
zmaz; // aby sa grafická plocha zobrazila už pri štarte
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i:integer;
begin
i:=1; while (i<=n) and not k[i].Blizko(X,Y) do inc(i);
if i<=n then
with k[i] do begin
Vpravo(15); Dopredu(50); Dopredu(-50);
end
else begin
inc(n); k[n]:=TKor.Create(X,Y);
with k[n] do begin
HP:=5; FP:=random(256*256*256);
Dopredu(50); Dopredu(-50);
end;
end;
end;
|
- použili sme korytnačiu preddefinovanú
funkciu (metódu) Blizko, ktorá
pre daný bod v rovine odpovie, či je
korytnačka od neho blízko
NDÚ
- nové korytnačky by mohli vznikať
na kliknutie so zatlačeným pravým
tlačidlom myši, na ľavé tlačidlo môže
korytnačka urobiť nejakú akciu - nakresliť
nejaký obrázok, alebo sa prilepí
na myš a do nasledujúceho kliknutia putuje
s myšou
Časovač
- predchádzajúcu úlohu,
v ktorej sme klikaním vytvárali
nové korytnačky, resp. ich otáčali
trochu pozmeníme: kliknutie na korytnačku
naštartuje kreslenie kružnice - a to pomaly
- použime známu procedúru cakaj
kliknutie naštartuje kružnicu:
|
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i,j:integer;
begin
i:=1; while (i<=n) and not k[i].Blizko(X,Y) do inc(i);
if i>n then begin
inc(n); k[n]:=TKor.Create(X,Y);
with k[n] do begin HP:=5; FP:=random(256*256*256); Dopredu(0); end;
end
else
with k[i] do
for j:=1 to 36 do begin
Dopredu(10); Vpravo(10);
cakaj(50); // sleep(50); Image1.Repaint;
end;
end;
|
- vzniká zaujímavý
efekt: kliknutie na korytnačku ju rozbehne -
počas tohoto klikania môžeme ďalej klikať
do plochy, na iné korytnačky - asi ľahko
odhalíte, že každé nové
kliknutie na korytnačku, zastaví predchádzajúci
pohyb a naštartuje nový pohyb - po skončení
tohoto nového pohybu sa dokončí
aj ten pozastavený...
- ak namiesto cakaj použijeme systémový
podprogram sleep (zakomentovaná
časť), tak sa tento efekt stratí: po
rozbehnutí korytnačky program nereaguje,
až kým korytnačka nedobehne celú
kružnicu
- celé je to spôsobené
tým, že v procedúre cakaj
je ukryté Application.ProcessMessages
- to znamená, že počas čakania 50
milisekúnd dovolíme Windows
reagovať na iné udalosti, napr. aj
na kliknutie myšou a teda umožníme
znovu naštartovať novú kružnicu (po
jej skončení sa pokračuje v prerušenej
akcii)
- procedúra sleep nemá
v sebe zabudované takéto mechanizmy
a preto je veľmi nebezpečná
- ukážeme iný spôsob,
ako sa rieši problém so spomaľovaním
akcií: použijeme nový komponent
časovač - Timer (z palety komponentov
System) - položíme ho niekam do plochy
- je to nevizuálny komponent a teda po
spustení aplikácie nebude zobrazený
- časovač si môžeme predstaviť ako hodiny,
ktoré s nejakou frekvenciou "tikajú"
- pri každom tiknutí môžu
vykonať nejakú akciu
- frekvenciu "tikania" nastavíme
v stavovej premennej Interval, pozastavenie
/ naštartovanie časovača môžeme urobiť
logickou stavovou premennou Enabled -
true znamená, že hodiny bežia,
false znamená, že sme ich pozastavili
- časovač má jedinú udalosť
onTimer, ktorá sa naštartuje po
uplynutí "tikacieho" intervalu,
t.j. zodpovedá jej procedúra Timer1Timer
- v nasledujúcom príklade predpokladáme
časovač so sekundovým tikaním,
t.j. Interval je 1000; korytnačka bude
kresliť úsečku dĺžky 100 a každú
sekundu sa otočí o 6 stupňov
sekundová ručička:
|
var
k:TKor;
procedure TForm1.FormCreate(Sender: TObject);
begin
k:=TKor.Create; k.HP:=5;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
zmaz;
k.Vpravo(6);
k.Dopredu(100);
k.Dopredu(-100);
end;
|
- príklad s korytnačkami, ktoré
sa po kliknutí rozbehnú po kružnici
preprogramujeme pomocou časovača: pre každú
korytnačku si budeme pamätať v poli kolko,
koľko krokov po kružnici ešte musí prebehnúť
korytnačky krúžia po svojich kružniciach:
|
var
k:array[1..100] of TKor;
kolko:array[1..100] of integer;
n:integer = 0;
procedure TForm1.FormCreate(Sender: TObject);
begin
zmaz;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i:integer;
begin
i:=1; while (i<=n) and not k[i].Blizko(X,Y) do inc(i);
if i>n then begin
inc(n); k[n]:=TKor.Create(X,Y);
with k[n] do begin HP:=8; Dopredu(0); HP:=3; end;
kolko[n]:=0;
end
else begin
k[i].FP:=random(256*256*256); kolko[i]:=36;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i:integer;
begin
for i:=1 to n do
if kolko[i]>0 then
with k[i] do begin
Dopredu(10); Vpravo(10);
dec(kolko[i]);
end;
end;
|
- časovaču Timer1 sme nastavili Interval
na 50 milisekúnd
- na záver ukážeme príklad
práce s časovačom a bitmapami: na nejakom
pozadí, napr. na fotografii tiger.bmp
sa bude pomaly pohybovať nejaký obrázok,
napr. opica.bmp - táto sa bude
odrážať od bočných stien grafickej
plochy ako lopta od stien miestnosti (v súbore
opicatiger.zip
sú obidve bitmapy)
- okrem grafickej plochy (Image1) umiestnime
časovač Timer1 s premennou Intreval
nastavenou na 100
jednoduchá animácia:
|
var
pozadie,obr:TBitmap;
x,y,dx,dy,x2,y2:integer;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=true;
pozadie:=TBitmap.Create;
pozadie.LoadFromFile('tiger.bmp');
obr:=TBitmap.Create;
obr.LoadFromFile('opica.bmp');
obr.TransparentColor:=clWhite;
obr.Transparent:=true;
x:=100; y:=50; dx:=3; dy:=4;
x2:=obr.Width div 2; y2:=obr.Height div 2;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Image1.Canvas.Draw(0,0,pozadie);
// Image1.Canvas.StretchDraw(Image1.ClientRect,pozadie);
inc(x,dx); if (x<x2)or(x>=Image1.Width-x2) then dx:=-dx;
inc(y,dy); if (y<y2)or(y>=Image1.Height-y2) then dy:=-dy;
Image1.Canvas.Draw(x-x2,y-y2,obr);
end;
|
- namiesto Draw pri kreslení
pozadia môžeme použiť aj iné prostriedky,
napr. vykachličkovanie alebo StretchDraw,
ale tie môžu výrazne spomaliť priebeh
animácie
NDÚ
- umiestnite do plochy väčší počet
korytnačiek - napr. pravidelne ich rozmiestnite
na priamke alebo kružnici a nechajte sa ich
hýbať podľa nejakých pravidiel,
napr. rôznou rýchlosťou po kružnici,
alebo kmitať hore - dolu, tiež s rôznou
rýchlosťou - napr. prvá nech má
rýchlosť 1, druhá 1.1, tretia
1.2, ...
|