[delphi] geneste objecten parent properties aanspreken

Pagina: 1
Acties:
  • 163 views sinds 30-01-2008
  • Reageer

  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ik ben bezig om een applicatie in delphi te schrijven. ik gebruik veel zelfgemaakte objecten, en een veel voorkomende structuur bij mij is deze:
Delphi:
1
2
3
4
5
6
TMijnObject = class
  mijnsubobject: TMijnanderObject;
  width, height: integer;
  constructor create(AOwner: TComponent);
  {hier nog veel meer properties en methodes}
end;

er zit hier dus een object in een object. in de constructor van de parent maak ik als volgt meteen een instance van het subobject:
Delphi:
1
2
3
4
5
6
7
8
constructor TMijnObject.Create(AOwner: TComponent);
begin
  self.Owner := AOwner;
  self.mijnsubobject := TMijnanderObject.Create(self); {constructor ziet er globaal hetzelfde uit als deze}
  self.mijnsubobject.parent := self;
  self.width  := 200;
  self.height := 200;
end;

ik wijs dus een owner toe namelijk het eigen object. en ik wijs een parent toe, ook het eigen object.
ook geef ik het parent object een width en een height in de constructor.
mijn probleem is nu dit. als ik vanuit mijn childobject's constructor de parent aan wil spreken, dan krjig ik een runtime error. mijn progsel crashed dus. ik wil bijvoorbeeld vanuit de constructor van mijn child, de width en height overnemen van mijn parent (zonder extra argumenten in mijn constructor mee te geven). dus:
Delphi:
1
2
3
4
5
TMijnanderObject.create(AOwner: TComponent);
begin
  self.Owner := AOwner;
  self.width  := self.parent.width; {en dit is dan de boosdoener}
end;

na wat debuggen kom ik steeds tot de conclusie dat de fout hem ergens in de parent/child relatie zit. de 'parent' veroorzaakt steeds een fout. ik kom er echt niet uit. ik heb ook hier op GoT al verschillende draadjes gelezen over parent/child dingen, maar daar wordt mijn probleem niet door opgelost. ook ben ik volledig op de hoogte van het verschil tussen owner en parent :p. ik hoop dat ik alles duidelijk heb uitgelegd.

nogmaals, mijn probleem is dus dat ik vanuit een child geen parent aan kan spreken. heeft iemand enig idee hoe ik dit op kan lossen?

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Zie ie zo inherited; aanroepen als aller eerste regel van elke constructor. En dan de parent meegeven in de constructor van het TMijnanderObject.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
constructor TMijnObject.Create(AOwner: TComponent); 
begin 
  inherited;

  self.Owner := AOwner; 
  self.mijnsubobject := TMijnanderObject.Create(self, Self); {constructor ziet er globaal hetzelfde uit als deze} 
  self.width  := 200; 
  self.height := 200; 
end;

TMijnanderObject.create(AOwner: TComponent; Parent: TComponent); 
begin 
  self.Owner := AOwner; 
  self.Parent := Parent;
  self.width  := self.parent.width; {en dit is dan de boosdoener} 
end;


Of de parent vergeten en aanmenen dat de owner ook de parent is.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
waarom moet je een extra parent argument meegeven als je op het moment van instantieren al een parent zet. inherited roep ik idd overal aan. en hij slikt dat extra parent argument niet als ik mijn object afleidt van een TPaintBox, terwijl ik toch de constructor override.

das waar ook ja. als je override dan kun je geen extra argumenten meegeven.
maar hoe moet ik het dan oplossen?

[ Voor 18% gewijzigd door tombo_inc op 23-12-2005 16:19 ]

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Tombo_inc schreef op vrijdag 23 december 2005 @ 16:05:
waarom moet je een extra parent argument meegeven als je op het moment van instantieren al een parent zet.
Omdat je eerst de constructor aanroept en pas als die klaar is op de volgende regel de parent zet. Je zet de parent dus te laat voor de code in de 2e constructor.
en hij slikt dat extra parent argument niet als ik mijn object afleidt van een TPaintBox, terwijl ik toch de constructor override.
Dan doe je toch iets niet goed.
das waar ook ja. als je override dan kun je geen extra argumenten meegeven.
maar hoe moet ik het dan oplossen?
Een eigen constructor maken met die extra parameter en die dan aanroepen.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ja je hebt gelijk stom dat ik daar niet aan dacht.
en met dat eigen constructor maken. ik heb onder andere een class nodig die ik afleidt van een TPaintBox. mijn eigen functionaliteit implementeer ik dan gewoon door de constructor te overriden. het punt is alleen dat je bij overriden dezelfde argumenten moet hanteren als de orginele methode. ik heb ook al gekeken naar overloaden, maar dat snap ik nog niet helemaal :? O-) . hoe zou ik dat op moeten lossen?

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Delphi:
1
2
3
4
5
6
7
8
public
  constructor CreateWithParent(Owner: TComponent; Parent: TComponent);

// of

public
  constructor Create(Owner: TComponent); override; overload;
  constructor Create(Owner: TComponent; Parent: TComponent); overload;


Maar TComponents hebben al een Owner en een Parent en zijn soms gevoelig voor hoe je die (mis)gebruikt. Ik zou het dan zo aanhouden dat de parent zelf de properties zet van het child en niet de child zijn eigen properties.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
aha, ik zal eens gaan testen ermee.
ik snap je punt met dat de parent alle props zet. maar is het niet de bedoeling van een constructor om het object te initializeren? als je de parent alles laat zetten, is de constructor dan niet overbodig? en wat is dan de parent en owner van zo'n TComponent standaard?

en ik heb nog een vraagje :9.
een parent (en ook owner) hoeft niet per definitie het bovenliggende object te zijn. is er een manier om het bovenliggend object aan te spreken vanuit het childobject zonder de parent of owner methode?

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Ok, laat ik het anders zeggen. Het is niet gebruikelijk dat je in de constructor van een component iets doet met de parent. De parent wordt pas later gezet of helemaal nooit.

Als je de owner en de parent niet wil gebruiken kan je zelf wat maken op dezelfde manier.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ok dat is duidelijk :)
dus wat je dan doet is, je gebruikt een owner voor het geheugen management etc., een parent voor het tekenen etc. en je maakt zelf een property waarmee je een directe parent/child relatie mee kan maken. lijkt me wel een goed plan ja :P . (als ik iets verkeerds zeg, verbeter me dan aub :9 )

bedankt in ieder geval _/-\o_

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 18:21

Tomatoman

Fulltime prutser

Het valt me op dat er in jouw code een paar merkwaardigheden veelvuldig voorkomen.
Tombo_inc schreef op vrijdag 23 december 2005 @ 15:26:

Delphi:
1
2
3
4
5
6
TMijnObject = class
  mijnsubobject: TMijnanderObject;
  width, height: integer;
  constructor create(AOwner: TComponent);
  {hier nog veel meer properties en methodes}
end;
• Waarom maak je van mijnsubobject, width en height geen properties?
• Verder is het handig om de in Delphi gebruikelijke conventies voor hoofdlettergebruik te volgen: MijnSubobject, Width, Height, Create, Self, Parent. Een beetje vreemde eend in de bijt is Integer - het is een reserved word, maar wordt als uitzondering op de regel toch met een hoofdletter geschreven.
• Dan een tweede stukje code:
Delphi:
1
2
3
4
5
6
7
8
constructor TMijnObject.Create(AOwner: TComponent);
begin
  self.Owner := AOwner;
  self.mijnsubobject := TMijnanderObject.Create(self);
  self.mijnsubobject.parent := self;
  self.width  := 200;
  self.height := 200;
end;
Het gebruik van Self is hier overbodig. Binnen een object slaat een identifier (property, variabele, functienaam, enzovoort) automatisch op die identifier binnen dat object. De verwijzing naar het object met Self is daarom overbodig. Je kunt de code eenvoudigweg schrijven als:
Delphi:
1
2
3
4
5
6
7
8
constructor TMijnObject.Create(AOwner: TComponent);
begin
  Owner := AOwner;
  MijnSubobject := TMijnAnderObject.Create(Self);
  MijnSubobject.Parent := Self;
  Width := 200;
  Height := 200;
end;

Een goede grap mag vrienden kosten.


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ja dat klopt.
normaliter houd ik me gewoon aan die hoofdletter regels, maar dit stukje heb ik snel ff in de topic reply getyped. verder gebruik ik altijd self omdat ik dat netter vind, maar het hoeft inderdaad niet. dat width en height is een beetje onduidelijk,klopt. in mijn applicatie is mijnanderobject een afgeleide van TPaintBox en die heeft al een width en height. dat heb ik niet duidelijk vermeld nee. maar het ging hier even om het princiepe.

nog even ontopic.
klopt mijn reply hierboven mbt owner, parent, en eigen property. of moet het anders of beter.
wat is normaal gesproken de manier om het direct bovenliggende object aan te spreken vanuit het child. (want owner en parent hoeven niet per se het object te zijn dat direct het andere object bevat). en het is dus gewoon toegestaan om objecten op die manier te nesten neem ik aan?

offtopic:
tombo_inc is zichzelf de laatste tijd wat meer aan het verdiepen in delphi en OOP :9

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Ja, dat is toegestaan. Ik vind het alleen een beetje vreemd dat je dit doet met TPaintBox en andere TComponent afgeleide. Ben je hier niet de presentatie met de logica aan het mixen? Misschien moet je eens kijken naar Model View Controller.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
nou wat ik probeer te maken is het volgende.
ik maak een eigen visuele canvas class (afgeleide van TPaintBox). dat is een canvas die je kan resizen en die ook zichtbaar is voor de gebruiker (omlijning etc). die class heeft als eigenschap onder andere een aantal layers. die layer class maak ik ook zelf (afgeleide van TPaintBox). op die layers gaat getekend worden. de canvas class houd een TObjectList bij met alle layers die hij bezit. uiteindelijk is een layer dus een eigenschap van de canvas class. een layer moet dezelfde afmetingen hebben als zijn canvas. mijn idee was dus om in een constructor van zo'n layer class de afmetingen van zijn parent over te nemen. vandaar dat ik de directe parent aan wil kunen spreken. ik hoop dat het zo een beetje duidelijk is.

als er nog tips/suggesties zijn over hoe ik het beter of anders moet doen, dan hoor ik het graag. ik ben namelijk nog niet zo heel ervaren met OOP. O-)

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 18:21

Tomatoman

Fulltime prutser

Tombo_inc schreef op zondag 25 december 2005 @ 12:33:
verder gebruik ik altijd self omdat ik dat netter vind, maar het hoeft inderdaad niet.
Ik vind het netter om Self niet te gebruiken als het niet nodig is. :)
nog even ontopic.
klopt mijn reply hierboven mbt owner, parent, en eigen property. of moet het anders of beter.
wat is normaal gesproken de manier om het direct bovenliggende object aan te spreken vanuit het child. (want owner en parent hoeven niet per se het object te zijn dat direct het andere object bevat). en het is dus gewoon toegestaan om objecten op die manier te nesten neem ik aan?
Owner en Parent hoeven inderdaad niet hetzelfde te zijn. Als ze dezelfde betekenis zouden hebben, zou een van beide ook overbodig zijn. :)

De Parent property geeft aan op welke TWinControl de control wordt geplaatst. Dimensies zoals Left en Width worden ten opzichte van de Parent aangegeven.

De Owner property van een TComponent geeft aan dat zodra Owner wordt vernietigd, Owner automatisch de TComponent zal vernietigen. Anders gezegd: de Owner zal alles vernietigen wat hij ownt.

Als je jouw probleem op een nette manier aanpakt, maak je in de constructor een TPaintBox, die je in de destructor vernietigt. Je implementeert SetBounds zodanig dat hij daar altijd de TPaintBox resizet. Tenslotte implementeer je de OnPaint method van de TPaintBox. Normaliter zul je iets schrijven als volgt:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
type
  TMijnControl = class(TWinControl)
  private
    FPaintBox: TPaintBox;
    procedure PaintBoxPaint(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  end;

implementation

procedure TMijnControl.PaintBoxPaint(Sender: TObject);
begin
  with FPaintBox.Canvas do
  begin
    Brush.Color := clRed;
    Brush.Style := bsBDiagonal;
    FillRect(BoundsRect);
  end;
end;

constructor TMijnControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);            // Niet vergeten!

{ De TMijnControl instantie wordt de owner van FPaintBox via Create(Self).
  Je zou ook Create(nil) kunnen gebruiken, zodat Owner nil blijft. }
  FPaintBox := TPaintBox.Create(Self);
  FPaintBox.BoundsRect := ClientRect;
  FPaintBox.OnPaint := PaintBoxPaint;
  FPaintBox.Parent := Self;
end;

destructor TMijnControl.Destroy;
begin
  FPaintBox.Free; { Niet nodig omdat FPaintBox.Owner al is ingesteld, maar
                    een goede gewoonte om Free expliciet aan te roepen. Als
                    FPaintBox.Owner nil is, is Free natuurlijk verplicht. }
  inherited Destroy;
end;

procedure TMijnControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  inherited;
  FPaintBox.BoundsRect := ClientRect;
end;
Het is in de meeste gevallen echter beter om niet een TPaintBox op een TWinControl te zetten, maar een descendant van TGraphicControl of TCustomControl te schrijven. Die hebben al een Canvas property, zodat je geen TPaintBox meer nodig hebt. Zie de helpfiles voor meer informatie welk van beide in jouw geval de beste class is om als base class te gebruiken.

Een goede grap mag vrienden kosten.


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
hartstikke bedankt!
dit komt in grote lijnen overeen wat ik al deed namelijk het volgende.
ik heb een form. dit form is de container van het document, meer niet.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type
  TDocumentContainerForm = class(TForm)
    
  private
    { Private declarations }
  public
    { Public declarations }
    Document: TDocument;

    constructor Create(AOwner: TComponent); override;
  end;

 {mijn constructor werkt zo:}
constructor TDocumentContainerForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  self.DoubleBuffered     := true;
  self.Document            := TDocument.Create(self);
  self.Document.Parent := self;
end;


vervolgens heb ik een class TDocument, dat mijn document representeerd. dat is die visuele canvas.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
type
 TDocument = class(TPaintBox)
  private
    {boel meuk}
    Layers: TObjectList;
  public
    constructor Create(AOwner: TComponent); override;
    procedure DocumentPaint(Sender: TObject);
   {nog meer meuk}
 end;

{de constructor}
constructor TDocument.Create(AOwner: TComponent);
var Layer: TLayer;
  begin
   inherited Create(AOwner);
   //self.SetSubComponent(true); niet op letten :p

   self.Constraints.MinWidth  := 25;
   self.Constraints.MinHeight := 25;

   self.OnPaint := DocumentPaint;
  
   self.Left     := 0;
   self.Top     := 0;
   self.Width  := 500;
   self.Height := 300;
   
   self.Layers   := TObjectList.Create(true);
   Layer  := TLayer.Create(self);
   Layer.Parent := self.Parent;
   self.Layers.Add(Layer);
  end;

het zaakje word geinitialiseerd en er word meteen een nieuwe layer gemaakt.

tenslotte heb ik nog een TLayer class.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type
  TLayer = class(TPaintBox)

  public
    constructor Create(AOwner: TComponent); override;
    procedure LayerPaint(Sender: TObject);
  end;


{constructor}
constructor TModelLayer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  self.SetSubComponent(true);
 
  //self.Width  :=   self.parent.Width; {dit was dus mijn eerste probleem}
 
end;


en dat is nu opgelost ;). uit alle reacties concludeer ik dat je vanuit een constructor (nagenoeg) nooit een parent aanspreekt. maar dat je de parent de nodige zaken laat zetten. wat ik ook geleerd heb is dat je met BoundsRect meteen de grootte van een object kan zetten. wat betreft die TPaintBox of GraphicControl daar zal ik idd eens naar kijken. je moet dus ook de setbounds overriden en zo maken dat hij meteen je childpaintbox resized zie ik uit je voorbeeld. dat lijkt me ook logisch ja :)

wat ik dan nog zie, is dat jij meteen een TPaintBox als property neemt. wat ik doe is een eigen class maken die afgeleid is van TPaintBox en daar dan alles in implementeren. jij implementeerd alles in de parentclass (als ik het goed zie). wat is beter of wat zijn de voordelen van die manier?

offtopic:
ik ben soms nogal precies. omdat ik het altijd zo netjes mogelijk wil maken. ik hoop niet dat het te irritant is met al die vragen

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 18:21

Tomatoman

Fulltime prutser

Tombo_inc schreef op zondag 25 december 2005 @ 15:25:
[...] vervolgens heb ik een class TDocument, dat mijn document representeerd. dat is die visuele canvas.
Delphi:
22
   self.OnPaint := DocumentPaint;
Dit is niet goed. Wat gebeurt er nou als je ergens anders in je code dit doet?:
Delphi:
1
2
MijnDoc := TDocument.Create(Self);
MijnDoc.OnPaint := MijnOnPaintEventHandler;
Dan wordt opeens je document niet meer getekend zoals je in DocumentPaint hebt geïmplementeerd. Kortom: bug. De juiste aanpak is de Paint procuedure overriden en de OnPaint handler met rust laten.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
type 
 TDocument = class(TPaintBox) 
  protected
    procedure Paint; override;
 end; 

procedure TDocument.Paint;
begin
  inherited; { De inherited Paint procedure implementeert o.a. het
               OnPaint event. }

  { Doe hier je tekenwerk }
end;
De DocumentPaint procedure vervalt dan, net als regel 22.

Misschien is het handig om eens wat meer te lezen over het schrijven van componenten. Je bent al een aardig eind op weg, maar wat meer theoretische kennis is nooit weg. :)

Een goede grap mag vrienden kosten.


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ok :D nogmaals heel erg bedankt. zo leer je nog eens wat. :p
je laat dus gewoon de onpaint met rust, en implementeerd je teken gebeuren meteen in je paint procedure. (als ik het goed onthouden heb dan wordt de paint procedure aangeroepen nadat het object een WM_PAINT message oid ontvangt.)
moet of kan je dit bij alle events doen (ik geloof het niet maar wil het toch weer even verifieren O-) ). of moet je bijvoorbeeld een mousemove event wel op die manier (self.onmousemove := mijnfunc;) toekennen en zelf een procedure schrijven?

ik zal eens op zoek gaan naar wat sappige literatuur over dit onderwerp :9 .
ik neem overigens aan dat de rest van mijn progwerk wel goed is dan?

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Het zou het mooist zijn als je dit bij alle events doet. De meeste events hebben een virtuele DoEventName procedure die speciaal daarvoor is.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ok, maar je zegt de meeste events. ik heb net namelijk even in de delphi help gezocht en ik kon er bijvoorbeeld DoMouseMove niet in terug vinden. is er ergens anders nog een lijst waar je die dingen kan vinden of moeten ze gewoon in de help voorkomen?

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


Verwijderd

Helaas, dit soort meer 'low level' zaken staan niet in de online help...
En LordLarry heeft gelijk dat er vaak DoEventName procedures bestaan, maar het mouse move event is nou net 1 van de uitzonderingen:

In TControl wordt de OnMouseMove event handler afgehandeld in de MouseMove procedure (en da's ook het enige dat die procedure doet), die weer wordt afgevuurd vanuit de WMMouseMove message handler (die reageert op Windows WM_MOUSEMOVE messages).

[edit] Als erg interessant leesvoer voor het maken van componenten kan ik je "Developing Custom Delphi 3 Components" van Ray Konopka aanraden. Helaas niet meer in boekvorm te krijgen, maar Ray biedt 'm nog wel aan als PDF, voor de (m.i. belachelijk hoge) prijs van $25. Maar ja, 't is z'n geld eigenlijk wel meer dan waard.
En 't mag dan geschreven zijn voor Delphi 3, maar de inhoud is zelfs in Delphi 2006 nog prima toepasbaar.

't Is te bestellen via Raize.com.

[edit2] Ik zie net dat TControl.MouseMove wel in de online help staat, maar als je niet weet hoe die procedure heet, is 't lastig zoeken. En aangezien MouseMove als Protected gedefinieerd is, zal Code Insight je ook niet zo gek ver helpen.
Maar voor dat laatste is een simpel trucje: definieer in de unit waar je bij de protected methods/properties wilt een eigen afgeleide die helemaal niks toevoegt aan de class die je wilt hebben, bv.
Delphi:
1
THackPaintBox = class(TPaintBox);

et voila, je kunt ook rechtstreeks bij de protected delen. :)

[ Voor 68% gewijzigd door Verwijderd op 26-12-2005 01:13 ]


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ok, maar in feite is het dus het netste om die orginele procedures die de "onevent"events afvuren te overriden en meteen daar je meuk te implementeren. en als ik het goed begrijp heten veel van die dingen DoEventnaam, maar zijn er uitzonderingen die je maar moet zien te vinden :p. en zoals hierboven gezegd kun je beter de paint method overriden dan een eigen procedure aan een onpaint event koppelen. dit moet je dus proberen bij zoveel mogelijk events te doen begrijp ik uit jullie verhalen?

wat me dan nog verbaasd is waarom men dan de eventhandlers als onpaint en onmousemove erin gemaakt heeft? als je toch beter die functie kan overriden.

en bedankt voor de leestip, ik zal er eens naar kijken.

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


Verwijderd

Tombo_inc schreef op maandag 26 december 2005 @ 13:31:wat me dan nog verbaasd is waarom men dan de eventhandlers als onpaint en onmousemove erin gemaakt heeft? als je toch beter die functie kan overriden.
Niet iedere Delphi programmeur maakt componenten en afgeleiden op de manier zoals jij doet, maar de meesten maken gewoon gebruik van bestaande componenten, en vullen dan de benodigde gepublishte events etc. in. Wanneer je dan in het component al bv. de OnMouseMove handler inpikt, ontneem je ze de mogelijkheid om design time die handler zelf te gaan gebruiken.
Vandaar dat 't bij het schrijven van een component (dat mogelijk ook door anderen gebruikt gaat worden) beter is om de Paint, MouseMove, DoMouseDown, etc. methods te overriden. En er dan natuurlijk wel voor zorgen dat de bijbehorende eventhandlers nog wel worden aangeroepen. ;)

  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
ja, dus als je een component maakt waarvan je zeker een bepaalde functionaliteit voor sommige events wil hebben, en je dus wilt niet dat anderen daar kortemetten mee kunnen maken, dan moet je de event methods overriden. daar implementeer je dan je hele handel, en zorg je dat de rest ook nog blijft werken. als iemand anders dan jouw component gaat gebruiken dan kan hij gewoon alles doen zonder dat jou functionaliteit naar de maan gaat. dat klinkt allemaal heel logisch ja :)
bedankt allemaal!

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
na nog een heleboel geprobeerd te hebben, werkt het nog steeds niet zoals ik zou willen. ik krijg namelijk nog een ding niet voor mekaar. ik heb nu dit:
een formulier:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type
  TDocumentContainerForm = class(TForm)
    
  private
    { Private declarations }
  public
    { Public declarations }
    Document: TDocument;

    constructor Create(AOwner: TComponent); override;
  end;

{ declareer globale variabelen }  
var
  DocumentContainerForm: TDocumentContainerForm;

implementation


{$R *.dfm}


constructor TDocumentContainerForm.Create(AOwner: TComponent);
begin
  inherited;
  
  //self.DoubleBuffered := true;
  self.Document        := TDocument.Create(self);
  self.Document.Parent := self;
end;

dan heb ik mijn eigen TDocument class:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type
 TDocument = class(TPaintBox)
  private
    Layers: TObjectList;
  public
    constructor Create(AOwner: TComponent); override;
 end;

 
implementation

constructor TDocument.Create(AOwner: TComponent);
var Layer: TLayer;
  begin
   inherited;
   
   self.Constraints.MinWidth  := 25;
   self.Constraints.MinHeight := 25;

   self.Left   := 0;
   self.Top    := 0;
   self.Width  := 500;              // default waarden
   self.Height := 300;
   
   self.Layers       := TObjectList.Create(true);
   Layer        := TLayer.Create(self);
   {Layer.Parent := self.parent;  dit moet op de een of andere manier goed geset worden. parent moet het formulier (TDocumentContainerForm) zijn. ik weet niet waar of hoe ik het moet doen.}
   self.Layers.Add(ModelLayer);
  end;

en mijn TLayer class:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type
  TLayer = class(TPaintBox)

  private
    Graphics: TObjectList;
  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

constructor TLayer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  self.SetSubComponent(true);
  self.width := 400;
  self.Height:=400;
end;


nu moet het formulier de parent zijn van beide classen, omdat ze daarop getekend moeten worden. op het moment dat de formulier gemaakt word dan instantieer ik in de constructor meteen een nieuw TDocument object en wijs ik het formulier als parent toe. dat werkt goed, en het document wordt getekend. echter, maak ik in de constructor van TDocument ook meteen een instantie aan van TLayer. maar daarvan krijg ik nog steeds de parent niet geset. de parent van TLayer moet het formulier zijn. de manier van de extra parameter in de constructor krijg ik niet voor mekaar gestumperd (ik krijg alleen maar runtime errors). en verder zou ik niks kunnen bedenken behalve heel erg inefficiente mutual dependancies.
zou iemand me kunnen vertellen hoe van dit uiterst irritante probleem af kom :) .

[ Voor 1% gewijzigd door tombo_inc op 27-12-2005 17:21 . Reden: typo ]

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Gebruik Model View Controller.

Of maak je eigen property die je gebruikt als Parent.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
constructor TDocument.Create(AOwner: TComponent);
var Layer: TLayer;
  begin
   inherited;
   
   self.Constraints.MinWidth  := 25;
   self.Constraints.MinHeight := 25;

   self.Left   := 0;
   self.Top    := 0;
   self.Width  := 500;              // default waarden
   self.Height := 300;
   
   self.Layers       := TObjectList.Create(true);
   Layer        := TLayer.Create(self);
   Layer.Document := Self;
   self.Layers.Add(ModelLayer);
  end;

// Layer class:
property Document: TDocument read FDocument write SetDocument;

procedure TLayer.SetDocument(Value: TDocument);
begin
  FDocument := Value;

  if Assigned(FDocument) then
    Parent := Value.Parent
  else
    Parent := nil;
end;


Of gebruik componenten die meer aansluiten wat je hier doet. Gebruik voor je Document geen paintbox, maar een TCustomControl afgeleide (TPanel). Je Layers kunnen dan je Document als Parent gebruiken ipv de Parent van de Parent. Lijkt ook logischer in jouw geval aangezien de Layers bij het Document horen, niet bij het Form.

We adore chaos because we like to restore order - M.C. Escher


  • tombo_inc
  • Registratie: December 2004
  • Laatst online: 10-03 13:21
hartstikke bedankt!
het werkt nu. :) ik heb nog eens gekeken naar de objecten die ik gebruik, en het is inderdaad veel logischer om TCustomControl afgeleide te nemen. nu hoef ik niet zo ingewikkeld te doen met parents en zo, want ik kan zo mijn childs direct aan hun directe parent toewijzen omdat een control ze zelf kan tekenen. ik had even wat eigenschappen van een control over het hoofd gezien |:( . maar nu komt alles goed. mijn dank is groot _/-\o_ .

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition

Pagina: 1