Šta je novo?

Property tipa record

hwfanatic

Čuven
Učlanjen(a)
13.02.2002
Poruke
659
Poena
630
Treba da napravim klasu ciji ce jedan od properties-a da bute nestandardnog tipa, i to tipa TCustom koji je slog. Recimo nesto ovako:

property Nebitno[Indeks: Word]: TCustom read Get write Set; default;
...
procedure TKlasa.Set(Indeks: Word; NewValue: TCustom)
begin
*
end;

Da je u pitanju array bilo kog osnovnog tipa, namesto zvezdice bi stajalo nesto ovako:

NekiTamoNiz^[Indeks]:=NewValue;

Medjutim, ovo ne radi za array slogova TCustom... Ne radi u smilsu da kompajliranje ne prodje, sa porukom "Left side can not be assigned to" na komandu Klasa.Nebitno.Nesto:=...

Recimo da znam zbog cega ovo ne prolazi, ali nemam pojma kako to da premostim. :(
 
Problem je u tome sto koristis record kao property. Glavnu prepreku bi izbegao tako sto bi umesto recorda koristio klasu koja nastaje od TPersistent - nikakvi ti drugi fieldovi ni metodi ne trebaju, samo deklarisi ta svoja polja kao public fields (ne properties). Vazno je samo da redefinises assign metod, npr:

[code:1]
TMojaKlasa = class(TPersistent)
public:
polje1: integer;
polje2: integer;
polje3: string;
procedure Assign(Source: TPersistent); override;
end;

...
dalja implementacija
...

procedure TMojaKlasa.Assign(Source: TPersistent);
begin
if Source is TMojaKlasa then
begin
polje1 := TMojaKlasa(Source).polje1;
polje2 := TMojaKlasa(Source).polje2;
polje3 := TMojaKlasa(Source).polje3;
end else
Inherited Assign(Source);
end;
[/code:1]

Pa ces nakon toga moci uvek da kazes nesto tipa:
MojNiz[indeks].Assign(nekaDrugiObjektMojeKlase);
i dodela je gotova i legalna.



Generalni savet za probleme ovog tipa -> koristi TCollection klasu. Odnosno, umesto svog recorda napravis klasu koja potice od TCollectionItem - dodas svoja polja, propertije i metode (opet redefinises assign, naravno) i tako si definisao taj mali element (recimo da se zove TArtikal). Zatim definises svoju klasu koja bi bila kontejner za ove atomske klase (recimo da se zove TArtikli) tako sto ces naslediti TCollection klasu - tako si eliminisao upotrebu arraya, a i dalje pristupas clanovima preko [index] vrednosti. Onda tu svoju kontejner klasu (TArtikli) mozes uvek slobodno da koristis kao property u nekoj desetoj klasi. Velika prednost je u tome sto nasledjujes mehanizam koji je za to pravljen i sve radi besprekorno - cak i prilikom design time editovanja dobijas default editore za elemente tipa TArtikal. Evo par poznatih primera gde se koristi kombinacija TCollection + TCollectionItem: klase TStatusBar (ima Panels[n]), THeader (sadrzi THeaderSections), sve klase koje koriste Columns, svi toolbarovi, TActionList sadrzi TAction i slicno. Uvek pored propertyja TCollection klase imas u ObjectInspectoru dugmence sa tri tackice za editovanje pojedinih Itema -> tako ces i ti imati ukoliko koristis ovaj mehanizam. Uzmi i pogledaj source VCL-a kako je uradjen recimo TStatusBar i bice ti sve jasno.
 
silverglider je napisao(la):
Generalni savet za probleme ovog tipa -> koristi TCollection klasu.
Hvala silverglider!
rpbow.gif

opet redefinises assign, naravno
A, zasto to?
Uzmi i pogledaj source VCL-a kako je uradjen recimo TStatusBar i bice ti sve jasno.
Ok, ne bas sve, ali sad mi je svakako jasnije.

Jedino bih te jos priupitao kako da Add funkciju (koja potice od TCollection) nagovorim da vraca adresu novonapravljenog TCollectionItem-a, radje nego objekat tog tipa...
 
opet redefinises assign, naravno.
- A, zasto to?

Pa da bi imao mehanizam dodeljivanja tih objekata;
- kada bi rekao da je ObjekatA := ObjekatB imao bi dva objekta koji imaju fakticki isti sadrzaj, ali time bi imao dva pointera koji pokazuju na istu lokaciju, sto znaci da bi daljom promenom jednog automatski promenio i drugi objekat.

- kada bi rekao ObjekatA.Assign(ObjekatB); imao bi situaciju da oba objekta imaju iste vrednosti, ali to su i dalje dva potpuno odvojena objekta koji su na razlicitim lokacijama -> dalja promena jednog od njih znaci promenu samo tog objekta.

Klasa TPersistent uvodi Assign metod i ako zelis ovaj mehanizam dodele, moras da kreiras svoju klasu tako da nasledi TPersistent ili neku od njenih naslednica i redefinises Assign tako da tacno mapira svako polje na odgovarajuce (zato sto nikada ne bi mogao da kazes record1:=record2, nego svaki member recorda moras posebno). Druga prednost Assign metoda je to sto dodeljujes odgovarajuci property propertyju. To znaci da ce dodela morati da prodje kroz "write" metod tog propertyja i samim time ce biti korigovana vrednost (ukoliko je write metod napisan tako da proverava/koriguje dodelu vrednosti - a trebao bi).
Treci faktor je kao u ovoj situaciji kada koristis TCollection mehanizam - da MORAS da ga redefinises, jer ostale metode u ovom nasledjivanju TCollection(Item) mehanizma koriste assign i ako ga ne uradis, sve ce se srusiti kao kula od karata.

Jedino bih te jos priupitao kako da Add funkciju (koja potice od TCollection) nagovorim da vraca adresu novonapravljenog TCollectionItem-a, radje nego objekat tog tipa...

Pa i vraca adresu tog objekta. Kreira ga i vrati adresu novokreiranog itema. Znaci, mozes bez problema da koristis jedan privremeni pointer u nekoj petlji tipa:
[code:1]
var tmpObject: TMyClass;
while not MyTable.EOF do
begin
tmpObject := MyCollection.Add;
tmpObject.polje1 := MyTable.FieldByName('polje1').asInteger;
tmpObject.polje2 := MyTable.FieldByName('polje2').asInteger;
tmpObject.polje3 := MyTable.FieldByName('polje3').asString;
MyTable.Next;
end;
[/code:1]
 
Nazad
Vrh Dno