![]() |
TObjectList: AV wenn OwnsObject := True
Ich habe eine Klasse von TPObjectList abgeleitet, um dort "Seiten" zuverwalten. Jede Seite ist ein Objekt. Die Klasse sieht wie folft aus:
Delphi-Quellcode:
Setze ich nun OwnsObjects auf True und fü+ge mehr als ein Objekt der Liste hinzu, kommt es zu einer AccessViolation, wenn die Liste bei Programmende freigegeben wird:
type
TPageCollection = class(TObjectList) private function Get(Index: Integer): TImageEnVect; public Constructor Create; procedure Add(Item: TImageEnVect); procedure Insert(Index: Integer; Item: TImageEnVect); procedure Update(Index: Integer; Item: TImageEnVect); property Items[Index: Integer]: TImageEnVect read Get; function FindItemByName(Name: String): Integer; end; implementation { TPageCollection } constructor TPageCollection.Create; begin inherited; Self.OwnsObjects := True; end; ...
Delphi-Quellcode:
Was läuft da falsch?
procedure TForm1.FormCreate(Sender: TObject);
begin PageCollection := TPageCollection.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreeAndNil(PageCollection); end; |
Re: TObjectList: AV wenn OwnsObject := True
1. Ist nicht ownsObject immer (Default) auf true?
2. Gibst du vielleicht ein Objekt selber frei? Was anderes fällt mir jetzt auch nicht ein. |
Re: TObjectList: AV wenn OwnsObject := True
1.) Scheint so:
Zitat:
2.) Nein, tue ich eigentlich nicht. Aber auch, wenn ich keinen Constructor schreibe, kommt es zu einer AV beim Freigeben der Objektliste. |
Re: TObjectList: AV wenn OwnsObject := True
hast du mal versucht die anderen Prozeduren wie Add etc weg zu lassen? kommt das dann imernoch?
|
Re: TObjectList: AV wenn OwnsObject := True
Auch dann bekomme ich die AV. Als Objekte wird übrigens eine Imaging Komponente in der Liste gespeichert.
|
Re: TObjectList: AV wenn OwnsObject := True
Also bei mir sieht das so aus, Aufruf un freigeben genau gleich wie bei dir und ich bekomme keine AV
Delphi-Quellcode:
type
TPageCollection = class(TObjectList) public Constructor Create; end; implementation { TPageCollection } constructor TPageCollection.Create; begin inherited; Self.OwnsObjects := True; end; |
Re: TObjectList: AV wenn OwnsObject := True
Und was passiert, wenn du Objekte der Liste hinzufügst?
|
Re: TObjectList: AV wenn OwnsObject := True
Luckie fügt aber noch Objecte in die Liste ein ;-)
|
Re: TObjectList: AV wenn OwnsObject := True
Was steht denn bei dir in get bzw in add?
|
Re: TObjectList: AV wenn OwnsObject := True
ok hab folgende Funktionen hinzugefügt:
Delphi-Quellcode:
procedure AddImage(Item: TImage);
procedure TPageCollection.AddImage(Item: TImage); begin Add(Item); end; procedure TtfMain.Button1Click(Sender: TObject); begin PageCollection := TPageCollection.Create; PageCollection.Add(TImage.Create(Self)); end; procedure TtfMain.FormDestroy(Sender: TObject); begin FreeAndNil(PageCollection); end; und ich bekomme keine AV. Kann das Problem sein das due die Add Funktion der Objectliste überschreibst? |
Re: TObjectList: AV wenn OwnsObject := True
Hi Angel,
Du definierst bei Dir AddImage, benutzt aber nachher Add? Ist das gewollt oder nur ein Schreibfehler? |
Re: TObjectList: AV wenn OwnsObject := True
Ist en schreibfehler im Quelltext, aber funzt au so :wall: ist doch egal ich füge auf jedenfall ein TImage hinzu un gebe das ganze wieder frei :mrgreen:
|
Re: TObjectList: AV wenn OwnsObject := True
Ja, ich überschreibe die Add Methode, damit ich nur TImage Objekte in die Liste packen kann:
Delphi-Quellcode:
procedure TPageCollection.Add(Item: TImageEnVect);
begin inherited Add(Item); end; |
Re: TObjectList: AV wenn OwnsObject := True
Hi Michael,
sofern ich mich richtig erinnern kann, hatte ich so ein Problem auch mal. Es lag aber (wie in Deinem Fall die TPageCollection) an der Liste, sondern an den Objekten (in Deinem Fall TImageEnVect), die ich hinzugefügt habe. Evtl. steht etwas im Destructor von TImageEnVect, was die AV verursacht. |
Re: TObjectList: AV wenn OwnsObject := True
Zitat:
also hier sieht man doch eigentlich schon wie man es (imho) nicht machen sollte. Wenn der Owner (Self) angegeben wird, dann wird u.U. versucht das Image zweimal frei zu geben, einmal wenn durch PageCollection.Free (wenn OwnsObjects = True) und natürlich auch nochmal, wenn der Owner (also Self) frei gegeben wird. Das sollte beim zweiten mal also ordentlich krachen. Deswegen einfach mal den Owner durch nil ersetzen oder eben OwnsObjects auf false. Und ja, wundert mich dann natürlich auch, dass das hier überhaupt funktioniert. Imho dürfte es das eben nicht (ohne Fehler). Gruß der Unwissende |
Re: TObjectList: AV wenn OwnsObject := True
Ja also das das funktioniert würde ich auch sagen das im Destructor vom TImageEnVect was drin steckt was das verursacht. Ich habs jetzt auf alle möglichen Arten versucht, aber bekomme keine AV
|
Re: TObjectList: AV wenn OwnsObject := True
Hm, also ich habe beim Erstellen des Images nil als Owner angegeben. Vor hatte ich nämlich eine einfache TList genommen und wollte mich nun von der Last befreien, die Objekte selber frei geben zu müssen, was anstandslos geklappt hatte. (Schleife über alle Objekte und freigeben mit Free.) Weil ich auch zur Laufzeit Objekte rauslöschen will. Und da dachte ich, ist eine TObjectList bequemer.
Das Hinzufügen sieht dann so aus:
Delphi-Quellcode:
function TForm1.NewPage: TImageEnVect;
var ie : TImageEnVect; dpi : Integer; ieWidth : Integer; ieHeight : Integer; begin ie := TImageEnVect.Create(nil); with ie do begin Name := 'Page' + IntToStr(PageCollection.Count); Parent := Form1; Left := 200; Top := 10; Cursor := crArrow; DragMode := dmManual; dpi := GetDeviceCaps(GetDC(0), LOGPIXELSY); ieWidth := trunc((dpi / 25.4 * 197) * 0.5); ieHeight := trunc((dpi / 25.4 * 290) * 0.5); Width := ieWidth; Height := ieHeight; LayersSync := false; MouseInteract := [miMoveLayers, miResizeLayers]; Bitmap.Width := ieWidth; Bitmap.Height := ieHeight; Bitmap.Canvas.Brush.Style := bsClear; Bitmap.Canvas.Brush.Color := clWhite; Bitmap.Canvas.Rectangle(0, 0, ieWidth, ieHeight); Update; OnDragOver := ImageEnVectDragOver; OnDragDrop := ImageEnVectDragDrop; end; result := ie; end; procedure TForm1.btnNewPageClick(Sender: TObject); begin if Assigned(ImageEnVect) then PageCollection.Update(LBCurrentIndex, ImageEnVect); ImageEnVect := NewPage; PageCollection.Add(ImageEnVect); ListBox1.Items.Add(Format('Seite %d',[ListBox1.Count + 1])); LBCurrentIndex := ListBox1.Count - 1; //Listbox1.ItemIndex := LBCurrentIndex; //lblCurrPage.Caption := Format('Aktuelle Seite: %s', [PageCollection.Items[LBCurrentIndex].Name]); end; |
Re: TObjectList: AV wenn OwnsObject := True
Und was machst du im Destructor vom TImageEnVect?
|
Re: TObjectList: AV wenn OwnsObject := True
Zitat:
|
Re: TObjectList: AV wenn OwnsObject := True
Dein Problem dürfte sein (ohne jetzt alles genau gelesen zu haben, etc.), dass Du die Objekte vom Typ TImageEnVect (geile Bibliothek, gell ;)) sowohl Deiner Liste zufügst, als auch irgendeinem Container auf Deinem Form. Wenn Du jetzt das Form schließt, dann versucht sowohl der Container des Forms, in welchem die Objekte als Children dargestellt werden, als auch die Liste diese Objekte zu releasen.
Einer schafft es, der andere kommt zu spät mit der Freigabe et voilà, es kommt zur AV. Lösung: entweder vorm FormClose die Elemente wieder aus den Containern entfernen oder der Liste verbieten die Objekte auch freizugeben (OwnsObjects := False;). ...:cat:... |
Re: TObjectList: AV wenn OwnsObject := True
Zitat:
|
Re: TObjectList: AV wenn OwnsObject := True
Gar nichts. Den habe ich nicht überschrieben, das ist noch der original Destruktor von der Komponente. Allerdings liegen auf der Komponete noch andere Objekte, die zu der Komponente gehören, wie Layer usw. Allerdings bekomme ich auch eine AV, wenn sich dort keine weiteren Objekte befinden.
Also vom Parent entferne ich sie nicht. Aber das hatte auch keine Probleme als ich noch mit TList gearbeitet habe und im Destruktor die Objekte von Hand mit Free freigegeben habe. @sakura: Wie gesagt, die TImageEnVect Komponenten, die ich dynamisch erstelle liegen nur in meinem eigenen Container von Typ TObjectList. Sie haben zwar das Formular als Parent aber das sollte ja eigentlich nicht stören. Und wenn ich OwnsObjects auf False setze, dann muss ich mich ja wieder selber um das Freigeben kümmern, was ich ja eigentlich vermeiden wollte. PS: @sakura: Hast du mit diesen Komponenten schon eigene Erfahrungen gemacht? Ich hätte da nämlich noch das ein oder andere Problem. Und die Newsgroup war bisher noch nicht sehr hilfreich. |
Re: TObjectList: AV wenn OwnsObject := True
Hallo Michael,
Zitat:
Gruß Hawkeye |
Re: TObjectList: AV wenn OwnsObject := True
Ich habe auch auf Parent gesetzt, aber habs grade getestet und habe keinen Fehler bekommen :gruebel:
|
Re: TObjectList: AV wenn OwnsObject := True
Das heißt, ich müsste den Destruktor dann trotzdem noch mal überschreiben und dort dann so was machen:
Delphi-Quellcode:
Womit ja dann in meinem Fall eine ObjectListe keine weiteren Vorteile zu einer normalen Liste bildet, da ich ja in beiden Fällen den Destruktor überschreiben müsste.
var
i: Integer; begin for i := 0 to self.Count - 1 do self.Items[i].Parent := nil; inherited; |
Re: TObjectList: AV wenn OwnsObject := True
Ist das ein großes projekt? Oder kannst du das mal hier als Anhang anheften damit man sich das mal genau anschauen kann?
Edit: Aargh du hast ja ne 3rd party Kompo drinne :wall: |
Re: TObjectList: AV wenn OwnsObject := True
Noch ist es nicht groß. Aber es verwendet eben eine Fremdkomponente, die man erst installieren müsste. Desweiteren mache ich das für die Firma und ich scheue mich etwas, das hier online zu stellen.
|
Re: TObjectList: AV wenn OwnsObject := True
|
Re: TObjectList: AV wenn OwnsObject := True
Auch damit bekomme ich eine AV, auch wenn ich im Destruktor den parent auf nil setze:
Delphi-Quellcode:
Das ist irgendwie alles nichts. Ich glaube, ich bleibe doch bei meiner TList. :?
self.Items[i].Parent := nil;
|
Re: TObjectList: AV wenn OwnsObject := True
Also ich hab jetzt spasseshalber mal alle Komponenten vom Formular hinzugefügt und das ganze freigegeben.. kein Fehler..
|
Re: TObjectList: AV wenn OwnsObject := True
Du musst das schon mit diesem TImageEnVect versuchen, alles andere hat keinen Sinn :roll:
|
Re: TObjectList: AV wenn OwnsObject := True
Zitat:
Am einfachsten ist es, wenn Du eine Liste von TComponentList ableitest, sagen wir mal TControlList. In dieser musst Du nur den Destruktor überschreiben und für alle Kinder vor dem Aufruf des geerbten Konstruktors dann etwas aufrufen wie:
Delphi-Quellcode:
Ach ja, natürlich darfst Du dann auch nur TControl-Instanzen einfügen.
var i: Integer;
begin if self.OwnsObjects and (self.Count > 0) then begin for i := 0 to self.Count - 1 do begin self[i].Parent.RemoveControl(self[i]); end; end; inherited destroy; end; |
Re: TObjectList: AV wenn OwnsObject := True
Zitat:
Edit: jetzt wo ich die Kompos schon hab kannst des ding au ma schicken oder? |
Re: TObjectList: AV wenn OwnsObject := True
Hallo Leute,
ich habe jetzt noch einmal mit TComponentList und Delphi 6 getestet. Beliebig viele TImage-Komponenten (Owner=nil) werden dynamisch erzeugt und auf einem Panel abgelegt, zusätzlich werden Referenzen auf die TImages in einer TComponentList (OwnsObjects=True) gespeichert. Nach dem Zerstören des Panels und der damit verbundenen automatischen Freigabe der TImages enthält die TObjectList keine Elemente mehr. Beim Freigeben der Form kann somit in deren OnDestroy-Handler die Liste ohne Probleme freigegeben werden. Auch das Freigeben der Liste zur Laufzeit funktioniert, die TImages werden dann automatisch vom Panel entfernt. Das alles funktioniert ohne Änderung an der TComponentList. Der Fehler muß meiner Meinung nach im restlichen Code zu suchen sein - vielleicht in der Komponente TImageEnVect, wie Die Muhkuh ja in Beitrag #14 schon angedeutet hat. Gruß Hawkeye |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:10 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-2025 by Thomas Breitkreuz