![]() |
DynArray: array of TShape
Hallo,
bei mir kommt folgender Fehler, wenn ich ein dynamisches Array von TShape-Objekten machen möchte: [Fehler] USCtrl.pas(11): Undefinierter Bezeichner: 'TShape' Kann man keine Arrays von solchen Objekten machen? Wenn doch, wie? |
Re: DynArray: array of TShape
Hoi,
wie wärs mit bissle Code ?? |
Re: DynArray: array of TShape
Füg mal die Unit "ExtCtrls" in die Uses-Klausel ein.
|
Re: DynArray: array of TShape
Ok, danke, das hat diesen Fehler schonmal beseitigt.
Ich habe (versucht) eine Klasse zu schreiben, die in der Lage ist (so ziemlich) beliebig viele TShape-Komponenten zu erzeugen und zu verwalten. Sie enthält bis jetzt die Methoden
Delphi-Quellcode:
Die TShapes werden in einem Array gespeichert:
{ public-Teil }
procedure Move(x,y: integer; whichOne: integer = 0); { <- Position eines einzelnen oder aller Shapes verändern } procedure Del(whichOne: integer = 0); { <- Einzelne oder alle Shapes löschen } procedure Show(show: boolean = true; whichOne: integer = 0); { <- Einzelne oder alle Shapes anzeigen lassen } procedure Resize(width,height: integer; whichOne: integer = 0); { <- Größe eines einzelnen oder aller Shapes verändern } constructor Create(howMany,iWidth,iHeight: integer; { <- constructor, dem die "Startwerte" übergeben werden } BrushStyle: TBrushStyle = bsSolid; PenStyle: TPenStyle = psSolid; ParentDing: TWinControl); { <- ???} destructor Free; { <- destructor, der erst alle TShapes free't und dann die Klasse ansich }
Delphi-Quellcode:
In der Theorie sollte das funktionieren, doch ein paar Fehler sind noch drin.
{ private-Teil }
FShapeArray: array of TShape; Welchen Datentyp muss denn ParentDing im Constructor haben? Der sieht übrigends su aus:
Delphi-Quellcode:
Ich hoffe ihr könnt mir helfen...
constructor TShapeControl.Create(howMany,iWidth,iHeight: integer;
BrushStyle: TBrushStyle = bsSolid; PenStyle: TPenStyle = psSolid; Parent: TWinControl); { <- ??? } var i: integer; begin SetLength(FShapeArray, howMany); for i:=0 to high(FShapeArray) do FShapeArray[i] := TShape.Create(self); with FShapeArray[i] do begin parent := ParentDing; { <- ParentDing } height := iHeight; width := iWidth; left := 0; top := 0; brush.style := BrushStyle; pen.style := PenStyle; end; end; :dp: |
Re: DynArray: array of TShape
Moin Char,
als Parent solltest Du jedes WinControl nehmen können. Eine Kompo wird immer relativ zum Parent dargestellt. |
Re: DynArray: array of TShape
So, nun ist nurnoch ein Fehler drin:
[Fehler] USCtrl.pas(36): Inkompatible Typen: 'TComponent' und 'TSCtrl' Und zwar im Constructor wenn die einzelnen Shape-objekte erstellt werden:
Delphi-Quellcode:
Ich vermute, das ist, weil ich bei create(self) das self eben für meine Klasse TSCtrl steht, eigentlich aber etwas anderes sein sollte (ein TCOntrol eben).
constructor TShapeControl.Create(howMany,iWidth,iHeight: integer;
BrushStyle: TBrushStyle = bsSolid; PenStyle: TPenStyle = psSolid; ParentObj: TWinControl = nil); var i: integer; begin SetLength(FShapeArray, howMany); for i:=0 to high(FShapeArray) do begin FShapeArray[i] := TShape.Create(self); { <- Da ist der Fehler} with FShapeArray[i] do begin parent := ParentObj; height := iHeight; width := iWidth; left := 0; top := 0; brush.style := BrushStyle; pen.style := PenStyle; end; end; end; Mein Problem ist, dass ich überhaupt nicht weiß, warum bei TShape.create überhaupt ein Parameter angegeben werden muss, was er zu bedeuten hat und wie er in meinem Fall aussehen müsste. Genauso ist das beim Parameter meines Constructors ParentObj. Der muss nämlich einen Startwert haben. Ich hab einfach nil genommen, weil mir nichts besseres eingefallen ist. Am liebsten würde ich das so haben, dass als ParentObj standardmäßig das Hauptformular des Projektes genommen wird. Geht das? |
Re: DynArray: array of TShape
Moin Char,
von welcher Klasse ist denn TSCtrl abgeleitet? Der Owner den Du bei TShape.Create angeben sollst dient in gewisser Weise zur Resourcenverwaltung. Wird eine Komponente zerstört, die Owner für andere Objekte ist, werden diese auch zerstört. Gibst Du als Owner nil an, so musst Du selber dafür sorgen, dass die Objekt wieder freigegeben werden. |
Re: DynArray: array of TShape
TSCtrl ist selbst geschrieben (also dürfte dann von TObject abgeleitet sein).
Die Shapes werden sowieso selbst wieder zerstört, wenn das TSCtrl-Objekt gefreet wird oder fehlt da was?
Delphi-Quellcode:
destructor TShapeControl.Free;
var i: integer; begin for i:=0 to high(FShapeArray) do FShapeArray[i].Free; SetLength(FShapeArray,0); end; Also muss ich beim constructor TShape.create(nil) machen. Was muss nun als "Startwert" bei ParentObj stehen, damit TShape.parent gleich dem Hauptformular des Projektes ist? Oder geht nil da? |
Re: DynArray: array of TShape
Moin Char,
Zitat:
Delphi-Quellcode:
geschrieben hast. Das wäre dann identisch mit
type
TSCtrl = class //... end;
Delphi-Quellcode:
Den Destructor würde ich noch abwandeln:
type
TSCtrl = class(TObject) //... end;
Delphi-Quellcode:
Das inherited ist zwar bei Ableitung von TObject nicht zwingend erforderlich, da es hier nichts zu erben gibt, aber besser man gewöhnt sich dran, dann kann man es nicht so leicht vergessen, wenn es mal erforderlich ist.
destructor TShapeControl.Destroy;
var i: integer; begin for i:=0 to high(FShapeArray) do FShapeArray[i].Free; SetLength(FShapeArray,0); inherited; end; Bei dieser Konstruktion, bei der Du die Shapes selber wieder freigibst, kannst Du natürlich problemlos nil als Owner übergeben. Wenn das Hauptformular der Parent sein soll, dann solltest Du einfach dieses als Parameter im constructor übergeben. |
Re: DynArray: array of TShape
Delphi-Quellcode:
Du nimmst also Destroy statt Free. Warum? Was ist der Unterschied zu Free? Ich kenn mich damit nicht aus (merkt man sicher ;) ), aber sollte man normalerweise nicht Free benutzen?
destructor TSCtrl.Destroy;
var i: integer; begin for i:=0 to high(FShapeArray) do FShapeArray[i].Free; SetLength(FShapeArray,0); inherited; end; Was bedeutet/bewirkt inherited? Dann noch eine Frage: Wenn das Programm beendet wird, werden dann alle Objekte automatisch destroyed oder freed oder muss ich den destructor von meiner Klasse selbst aufrufen? Ich gehe von letzterem aus. Danke schonmal, es sind keine Fehler mehr zu finden. Nur eben diese Fragen noch. |
Re: DynArray: array of TShape
Moin Char,
der eigentliche destructor heisst i.d.R. Destroy. Free führt noch Prüfungen durch, bevor es dann Destroy aufruft. Die eigentliche Freigabe findet also in Destroy statt, das von Free aufgerufen wird. Nennen kannst Du den natürlich wie Du willst, aber Free ist von seinem Sinn her vorbelegt, so dass es zumindest ungeschickt wäre den destructor so zu nennen. Zudem ist es Konvention einen destructor Destroy zu nennen (genauso wie der constructor üblicher Weise Create heisst.) inherited heisst, dass die Methode gleichen Namens von der Basisklasse Deiner Klasse an dieser Stelle aufgerufen wird. Gibst Du hier noch einen Namen mit (z.B. inherited MethodenName) so wird die Methode "MethodenName" der Basisklasse aufgerufen. Ggf. sind dann noch Parameter zu übergeben. Stimmt Deine Deklaration mit der der Basisklasse überein kannst Du den Namen und die Parameter weglassen, da diese automatisch übernommen werden. BTW: Ich hab' hier auch Blödsinn geschrieben: :oops: "Das inherited ist zwar bei Ableitung von TObject nicht zwingend erforderlich, da es hier nichts zu erben gibt, " Man ruft ja den Destructor von TObject auf, und das sollte auch so sein. Jetzt musst Du nur noch darauf achten, an welcher Stelle das inherited gesetzt wird. Bei einem constructor sollte inherited als erstes aufgerufen werden, da es ja sinnvoll ist alles was von vorherigen Klassen stammt zu initialisieren, bevor man seine eigenen Ergänzungen initialisiert. Aus dem gleichen Grunde gehört inherited beim Destructor ans Ende. Erst einmal die eigenen Sachen aufräumen, dann dass was aus vorhergehenden Klassen stammt. Bei anderen Methoden die man überschreibt hängt es vom Zusammenhang ab, an welcher Stelle man das inherited einfügt. Meistens wohl als erstes, im Extremfall vielleicht auch gar nicht. Zitat:
|
Re: DynArray: array of TShape
Also muss in meinen Constructor auch inherited ja?
Wieso funktioniert es denn dann auch ohne? TSCtrl ist ja eine Ableitung von TObject, wieso wird das Objekt ordnungsgemäß erstellt, wenn gar nicht die Create-Prozedur von TObject aufgerufen wird, sondern "nur" meine? Und: Wieso geht inherited Free nicht? Free überprüft doch nur, ob das Objekt nicht vorher nil ist, weil Destroy alleine da nen Fehler ausgibt oder? Fragen über Fragen... [edit] Wenn ich inherited in den Constructor schreibe kommt folgende Fehlermeldung: [Fehler] USCtrl.pas(34): Inkompatible Typen Und wenn ich den Destructor umschreibe kommt eine Warnung: [Warnung] USCtrl.pas(22): Methode 'Destroy' verbirgt virtuelle Methode vom Basistyp 'TObject' Was ist überhaupt eine virtuelle Methode (virtual)? [/edit] |
Re: DynArray: array of TShape
Moin Char,
wenn Du es so schreibst
Delphi-Quellcode:
sollte es gehen.
type
TcsMyType = class(TObject) public constructor Create(const AsIrgendeinParameter : string); destructor Destroy; override; end; implementation { TcsMyType } constructor TcsMyType.Create(const AsIrgendeinParameter: string); begin inherited Create; // ... end; destructor TcsMyType.Destroy; begin //... inherited; end; Beim inherited im constructor musst Du den Aufruf der Basisklasse so mitgeben, wie er in der Basisklasse deklariert ist, wenn Deine Deklaration davon abweicht. Es wird vermutlich ohne inherited gehen, wenn in TObject.Create nichts initialisiert wird. Zum Thema virtuelle Methoden kannst Du ja erst einmal in der Hilfe unter eben diesem Begriff nachschlagen. Ich finde, dass ist da ganz gut erklärt. GGf. wäre es dann vielleicht sinnvoll mal einen neuen Thread aufzumachen, denn irgendwie sind wir hier, bezogen, auf Deine Eingangsfrage, schon lange OT ;-) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:37 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz