12.11.2002
|
čo sa budeme dnes učiť
- ako je naozaj definovaná trieda TKor
- obsahuje súkromné stavové
premenné a verejné stavové
premenné typu "vlastnosť"
- pri niektorých metódach je
pripojené rezervované slovo override,
overload alebo virtual
- uvidíme spôsob, ako sa vykresľujú
na obrazovku tvary korytnačiek
KorUnit
- podrobne sa pozrieme na programovú jednotku KorUnit
deklarácia triedy TKor:
|
type
TKor = class
private
FX,FY,FSmer:real;
FDole:boolean;
FFP:TColor;
FHP:integer;
public
constructor Create; overload;
constructor Create(nx,ny:real; uhol:real = 0); overload;
destructor Destroy; override;
procedure Dopredu(dlzka:real); virtual;
procedure Vpravo(uhol:real); virtual;
procedure Vlavo(uhol:real); virtual;
procedure ZmenSmer(uhol:real); virtual;
procedure ZmenXY(nx,ny:real); virtual;
procedure PresunXY(nx,ny:real); virtual;
procedure PH; virtual;
procedure PD; virtual;
procedure ZmenPero(ndole:boolean); virtual;
procedure ZmenFP(farba:TColor); virtual;
procedure ZmenHP(hrubka:integer); virtual;
procedure Pis(text:string); virtual;
function Smerom(nx,ny:real):real; virtual;
procedure Vypln(farba:TColor); virtual;
function Vzd(nx,ny:real):real; virtual;
function Blizko(nx,ny:real):boolean; virtual;
property X:real read FX;
property Y:real read FY;
property Smer:real read FSmer write ZmenSmer;
property Dole:boolean read FDole write ZmenPero;
property FP:TColor read FFP write ZmenFP;
property HP:integer read FHP write ZmenHP;
end;
|
- väčšinu vecí buď poznáme, alebo
sme s nimi už pracovali; môžeme tu vidieť niekoľko noviniek:
- všetky stavové premenné a metódy
sú rozdelené do dvoch veľkých skupín:
private a public
- okrem konštruktora Create je tu definovaný
aj deštruktor Destroy (s kľúčovým slovom
override)
- skoro za všetkými definíciami metód
je kľúčové slovo virtual, ktorého
význam sa budeme učiť neskôr
- konštruktor Create má predvolené parametre
(default hodnoty)
- niektoré stavové premenné (napr.
X, Y, Smer a pod.) sú uvedené kľúčovým
slovom property - vlastnosť
- postupne sa zoznámime s týmito novinkami
Privátne definície
- vieme, že v programovej jednotke (unit) môžeme
deklarácie uviesť nielen v interface časti, ale
aj za implementation, a teda vytvoriť buď verejné
definície alebo súkromné (len pre
potreby unitu)
- podobne je to pri definovaní triedy: definície
stavových premenných a metód môžeme
rozdeliť do dvoch skupín (neskôr uvidíme
aj ďalšie) private a public: na súkromné,
ktoré sú určené len pre potreby
samotného objektu a zvonku sú neprístupné,
a na verejné, ktoré zverejňujeme pre používateľov
(programátorov) tejto triedy
- to, že private stavové premenné
a metódy sú zvonku neprístupné
znamená, že ak nejakú triedu zadeklarujeme
v inteface časti nejakého unitu,
tak ostatné unity, ktoré túto
deklaráciu vidia, môžu pracovať
len s public deklaráciami ale
v implementation časti samotného
unitu sú všetky deklarácie rovnocenné
- pri práci s formulárom (napr. v triede
TForm1) môžeme vidieť, že niektoré prvky
(stavové premenné a metódy) nie
sú v ani jednej z týchto skupín
- okrem týchto dvoch skupín je aj ďalšia:
published, ktorá je skoro rovnaká ako
public, ale zatiaľ pre jednoduchosť predpokladajme,
že ju Delphi potrebujú pre komponenty a metódy,
ktoré sú zviazané s nejakým
formulárom
Predvolené parametre
- pri volaní procedúry (aj metódy)
môžem uviesť menší počet skutočných
parametrov ako je formálnych
- ak Delphi poznajú predvolené (náhradné)
hodnoty týchto parametrov, tak nehlásia
chybu, ale doplnia ich týmito hodnotami za nás
- predvolenými hodnotami môžu byť len
konštanty alebo konštantné výrazy
(niečo, čo vie kompilátor vypočítať
už počas kompilácie)
- len hodnotové alebo const parametre môžu
byť predvolené (default) - nie var-parametre
- za predvoleným parametrom (v zozname formálnych
parametrov) môžu nasledovať už len predvolené
- korytnačku môžeme skonštruovať napr. takto:
k:=TKor.Create(0,0,0); k:=TKor.Create(x,y);
- predvolený parameter je aj v definícii
procedúry zmaz:
procedure
zmaz(fpoz:TColor = clWhite);
- t.j. keď je volaná bez parametrov, farbou
pozadia fpoz bude biela, inak sa použije
zadaný parameter
Viac variantov jednej procedúry
- je to spôsob, pomocou ktorého môžeme
nazvať rôzne procedúry jedným
menom, resp. keď jedna procedúra má
viac variantov - aby pascal pri volaní takejto
procedúry správne rozhodol, ktorý
variant má použiť, musia sa tieto varianty
líšiť buď počtom parametrom alebo typmi parametrov
- v deklaráciách triedy - v deklarácii
metódy - za hlavičku procedúry zapíšeme
rezervované slovo overload
- toto slovo zapíšeme za všetky varianty
- vidíme dve
definície pre Create - oba varianty sa líšia
počtom parametrov
Vlastnosti (property)
- stavové premenné s kľúčovým
slovom property - sú špeciálne atribúty
triedy (nie sú to pamäťové položky
triedy ako v zázname)
- "skutočným" stavovým premenným
je vyhradené nejaké pamäťové
miesto (môžeme zistiť jej hodnotu, resp. ju meniť)
- to je analógia položkám záznamov
- "virtuálna" stavová premenná
- vlastnosť musí mať priradené nejaké
akcie na čítanie, resp. modifikovanie takejto
stavovej premennej
- pomocou tohoto mechanizmu môžeme kontrolovať
prístup ku "skutočným" stavovým
premenným alebo môžeme pre takéto
stavové premenné vypočítať ich
hodnotu, až keď budú požadované (čítané)
- syntax:
property meno:typ read položka|metóda
write položka|metóda;
- položka|metóda je buď obyčajná položka
(skutočná stavová premenná) objektu
(hoci aj privátna) alebo nejaká (hoci
aj privátna) metóda
- typ položky sa musí zhodovať s typom vlastnosti
- pre read - metóda musí byť bezparametrová
funkcia rovnakého typu ako typ vlastnosti
- pre write - metóda musí byť jednoparametrová
procedúra s hodnotovým alebo const parametrom
rovnakého typu ako typ vlastnosti
- jedna z častí read alebo write môže
chýbať => potom tento prístup nie je
povolený (napr. nedá sa meniť hodnota
stavovej premennej iba čítať)
- vždy, keď sa v programe bude čítať resp. meniť
hodnota takejto "virtuálnej" stavovej premennej
- vlastnosti, tak sa buď prečíta hodnota, resp.
priradí do položky, alebo sa zavolá príslušná
metóda
napr. korytnačka má tieto vlastnosti:
|
property X:real read FX;
property Y:real read FY;
property Smer:real read FSmer write ZmenSmer;
property FP:TColor read FFP write ZmenFP;
...
|
- čo znamená, že takúto stavovú
premennú X nemôžeme meniť (napr. priraďovacím
príkazom) - len čítať (vtedy dostaneme
hodnotu súkromnej premennej FX)
- vlastnosť Y je na tom rovnako
- vlastnosť Smer môžeme čítať
aj meniť - pri čítaní tejto premennej
sa vráti hodnota súkromnej premennej
FSmer, pri priradení do tejto premennej,
napr. k.Smer:=115;
sa zavolá metóda ZmenSmer(115);
- rovnako funguje napr. aj vlastnosť FP
(farba pera) - čítanie tejto premennej vráti
hodnotu súkromnej premennej FFP a
priradenie napr. k.FP:=clRed;
zavolá k.ZmenFP(clRed);
- V ďalšom príklade stavová premenná
- vlastnosť prem v skutočnosti manipuluje so súkromnou
premennou fprem, len pri jej čítaní sa
automaticky zvýši počítadlo poc
počítadlo čítania
premennej:
|
type
xx=class
private
fprem:real;
poc:integer;
function hodnota:real;
public
property prem:real read hodnota write fprem;
end;
function xx.hodnota:real;
// funkcia počíta počet prístupov ku stavovej premennej
begin
Result:=fprem; inc(poc);
end;
|
- neskôr uvidíme aj ďalšie možnosti stavových
premenných - vlastností
Deštruktor Destroy
- je podobný konštruktoru - automaticky sa zavolá
pri metóde Free, t.j. keď rušíme objekt,
môžeme na záver vykonať nejaké "upratovacie"
akcie (napr. uvolniť bitmapu, skryť korytnačku a pod.)
- volanie metódy obj.Free nejakého objektu
obj si môžeme zjednodušene predstaviť ako
if obj<>nil then obj.Destroy;
- takýto Free funguje len s deštruktorom
Destroy, hoci vo všeobecnosti by sme mohli
mať viac deštruktorov s rôznymi menami
Konštruktor a deštruktor korytnačiek
- Jednotka KorUnit má zadefinované dve súkromné premenné
(sú deklarované iba v implementation časti):
globálne premenné:
|
var
kory:array of TKor;
maxkor:integer = -1;
|
- v ktorých sa zapamätávajú
všetky vytvorené korytnačky - tento mechanizmus
slúži len ako ukážka práce
s dynamickým poľom a v tejto verzii programovej
jednotky KorUnit nemá veľký
význam
- dynamické pole kory slúži na zapamätanie si všetkých doteraz vytvorených
korytnačiek
- premenná maxkor obsahuje index maximálne
priradenej korytnačky v poli kory - pole kory nezväčšujeme
pri každej novej korytnačke o 1, ale raz začas zväčšíme
o 10 a maxkory je vtedy menšie ako High(kory)
- toto pole kory sa aktualizuje v TKor.Create a v TKor.Destroy
- premenná g:TCanvas slúži na kreslenie do grafickej plochy
- všimnite si, ako konštruktor Create inicializuje
stavové premenné:
konštruktor:
|
constructor TKor.Create(nx,ny,uhol:real);
var
i:integer;
begin
Inicializuj;
FX:=nx; FY:=ny; FSmer:=uhol;
FFP:=clBlack; FHP:=1;
FDole:=true;
i:=0; while (i<=maxkor) and (kory[i]<>nil) do inc(i);
if i>high(kory) then SetLength(kory, Length(kory)+10);
kory[i]:=self; if i>maxkor then maxkor:=i;
end;
|
- všimnite si ako druhý variant konštruktora
bez parametrov volá svoj prvý variant
s parametrami
druhý variant konštruktora:
|
constructor TKor.Create;
begin
Inicializuj;
Create(sirka/2,vyska/2);
end;
|
- aj deštruktor Destroy pracuje s poľom kory:
deštruktor:
|
destructor TKor.Destroy;
var
i:integer;
begin
i:=0; while (i<=maxkor) and (kory[i]<>self) do inc(i);
if i<=maxkor then kory[i]:=nil;
inherited;
end;
|
- inherited na záver metódy je ukážkou
toho, že netreba zabudnúť spustiť "upratovacie"
akcie aj pre triedu predka - v našom prípade
je to zbytočné, lebo predok triedy TKor má
prázdny deštruktor (trieda TKor je potomkom triedy
TObject)
V jednotke KorUnit sú okrem triedy TKor v interface
časti definované aj nejaké konštanty,
premenné a procedúry (a teda sú
viditeľné pre programy, ktoré majú
uses KorUnit;):
- Zmaz - má jeden predvolený parameter
- farbu pozadia grafickej plochy - bez parametra zmaže
grafickú plochu na bielo
- Cakaj - pozdrží vykonávanie
programu o zadaný počet milisekúnd
- počas tohoto čakania sa vykonáva Application.ProcessMessages
- premenné sirka a vyska obsahujú šírku
a výšku korytnačej grafickej plochy
KorUnit nemá ani časť initialization ani finalization
- lebo inicializácia premenných sa robí
až pri prvom TKor.Create, resp. pri NastavPlochu
- pozrime si inicializáciu, ktorá
sa spustí pred prvým vyvolaním
TKor.Create - jej najdôležitejšou úlohou
je nájsť v našej aplikácii nejakú
grafickú plochu (TImage) - nemá zmysel sa snažiť do detailov pochopiť,
ako to funguje
inicializácia:
|
procedure Inicializuj;
var
i,n:integer;
f:TForm;
begin
if g<>nil then exit;
f:=Application.MainForm;
if f=nil then begin
n:=Application.ComponentCount; i:=0;
while (i<n) and not (Application.Components[i] is TForm) do inc(i);
if i=n then begin
ShowMessage('vadná aplikácia - nenašiel som formulár');
Halt;
end;
f:=TForm(Application.Components[i]);
end;
n:=f.ControlCount; i:=0;
while (i<n) and not (f.Controls[i] is TImage) do inc(i);
if i>=n then begin
ShowMessage('vadná aplikácia - nenašiel som grafickú plochu');
halt;
end;
NastavPlochu(TImage(f.Controls[i]));
end;
|
- pomocná procedúra NastavPlochu
si požadovanú grafickú plochu (TImage)
zapamätá do premennej g, do premenných
sirka a vyska si uloží jej
rozmery a formuláru, v ktorom je grafická
plocha nastaví DoubleBuffered na true
pomocná procedúra NastavPlochu:
|
procedure NastavPlochu(p:TImage);
begin
if g<>nil then exit;
if p.Owner is TForm then
TForm(p.Owner).DoubleBuffered:=true;
g:=p.Canvas;
sirka:=p.Width; vyska:=p.Height;
end;
|
- ak túto procedúru zavoláme
s nejakou grafickou plochou pred prvým vytvorením
korytnačky, tak táto sa stane plochou pre
korytnačky - inak sa spúšťa mechanizmus automatického
hľadania "prvej" grafickej plochy
príklad s vlastnou triedou mojKor
- Malá ukážka potomka triedy TKor, ktorý
dodefinuje metódu na kreslenie binárneho
stromu:
odvodená trieda od TKor:
|
uses
KorUnit;
type
TMojaKor = class(TKor)
public
procedure strom(n:integer; s:real);
end;
procedure TMojaKor.strom(n:integer; s:real);
begin
dopredu(s);
if n>1 then begin
vlavo(45);
strom(n-1,s*0.67);
vpravo(90);
strom(n-1,s*0.67);
vlavo(45);
end;
dopredu(-s);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
k:TMojaKor;
begin
k:=TMojaKor.Create(250,400); // Create je zdedený
k.strom(5,150); // strom je metóda triedy TMojaKor
k.Free;
end;
|
- bolo by dobre, keby ste si zvykali dávať
definície nových tried do samostatných
programových jednotiek, napr. táto
trieda by bola definovaná v unite mojaKorUnit
a v unite s formulárom by sa iba používala:
mojaKorUnit.pas
|
unit mojaKorUnit;
interface
uses
KorUnit;
type
TMojaKor = class(TKor)
public
procedure strom(n:integer; s:real);
end;
implementation
procedure TMojaKor.strom(n:integer; s:real);
begin
dopredu(s);
if n>1 then begin
vlavo(45);
strom(n-1,s*0.67);
vpravo(90);
strom(n-1,s*0.67);
vlavo(45);
end;
dopredu(-s);
end;
end.
|
časť Unit1.pas
|
uses
mojaKorUnit;
procedure TForm1.Button1Click(Sender: TObject);
var
k:TMojaKor;
begin
k:=TMojaKor.Create(250,400); // Create je zdedený
k.strom(5,150); // strom je metóda triedy TMojaKor
k.Free;
end;
|
|