Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   TObjectList: AV wenn OwnsObject := True (https://www.delphipraxis.net/84818-tobjectlist-av-wenn-ownsobject-%3D-true.html)

Luckie 22. Jan 2007 12:39


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:
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;

...
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:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  PageCollection := TPageCollection.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(PageCollection);
end;
Was läuft da falsch?

sirius 22. Jan 2007 12:46

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.

Luckie 22. Jan 2007 12:52

Re: TObjectList: AV wenn OwnsObject := True
 
1.) Scheint so:
Zitat:

OwnsObjects is true (the default),
Aber warum kommt es zu einer AV, wenn ich es noch mal setze.

2.) Nein, tue ich eigentlich nicht.

Aber auch, wenn ich keinen Constructor schreibe, kommt es zu einer AV beim Freigeben der Objektliste.

Angel4585 22. Jan 2007 12:59

Re: TObjectList: AV wenn OwnsObject := True
 
hast du mal versucht die anderen Prozeduren wie Add etc weg zu lassen? kommt das dann imernoch?

Luckie 22. Jan 2007 13:02

Re: TObjectList: AV wenn OwnsObject := True
 
Auch dann bekomme ich die AV. Als Objekte wird übrigens eine Imaging Komponente in der Liste gespeichert.

Angel4585 22. Jan 2007 13:04

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;

Luckie 22. Jan 2007 13:07

Re: TObjectList: AV wenn OwnsObject := True
 
Und was passiert, wenn du Objekte der Liste hinzufügst?

Die Muhkuh 22. Jan 2007 13:07

Re: TObjectList: AV wenn OwnsObject := True
 
Luckie fügt aber noch Objecte in die Liste ein ;-)

sirius 22. Jan 2007 13:09

Re: TObjectList: AV wenn OwnsObject := True
 
Was steht denn bei dir in get bzw in add?

Angel4585 22. Jan 2007 13:11

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?

Die Muhkuh 22. Jan 2007 13:13

Re: TObjectList: AV wenn OwnsObject := True
 
Hi Angel,

Du definierst bei Dir AddImage, benutzt aber nachher Add? Ist das gewollt oder nur ein Schreibfehler?

Angel4585 22. Jan 2007 13:14

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:

Luckie 22. Jan 2007 13:16

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;

Die Muhkuh 22. Jan 2007 13:21

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.

Der_Unwissende 22. Jan 2007 13:22

Re: TObjectList: AV wenn OwnsObject := True
 
Zitat:

Zitat von Angel4585
Delphi-Quellcode:
procedure TtfMain.Button1Click(Sender: TObject);
begin
  PageCollection := TPageCollection.Create;
  PageCollection.Add(TImage.Create(Self));
end;

Hi,
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

Angel4585 22. Jan 2007 13:26

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

Luckie 22. Jan 2007 13:28

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;

Angel4585 22. Jan 2007 13:34

Re: TObjectList: AV wenn OwnsObject := True
 
Und was machst du im Destructor vom TImageEnVect?

Der_Unwissende 22. Jan 2007 13:37

Re: TObjectList: AV wenn OwnsObject := True
 
Zitat:

Zitat von Luckie
Hm, also ich habe beim Erstellen des Images nil als Owner angegeben.

Und Du entfernst die Controls auch wieder vom Parent, bevor Du die freigibst? Das wäre das Einzigste was mir noch einfällt, woran es scheitern könnte.

sakura 22. Jan 2007 13:40

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:...

sirius 22. Jan 2007 13:43

Re: TObjectList: AV wenn OwnsObject := True
 
Zitat:

Zitat von sakura
oder der Liste verbieten die Objekte auch freizugeben (OwnsObjects := False;).

dann aber mit update aufpassen...

Luckie 22. Jan 2007 13:45

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.

Hawkeye219 22. Jan 2007 14:17

Re: TObjectList: AV wenn OwnsObject := True
 
Hallo Michael,

Zitat:

@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.
Sakuras Hinweis noch einmal mit anderen Worten: ein TWinControl gibt im Destruktor alle in ihm liegenden Controls frei! Du kannst das von dir beobachtete Verhalten leicht mit der TImage-Komponente von Borland nachstellen. Ohne Lösen vom Parent knallt es, mit Lösen gibt es keine Probleme.

Gruß Hawkeye

Angel4585 22. Jan 2007 14:21

Re: TObjectList: AV wenn OwnsObject := True
 
Ich habe auch auf Parent gesetzt, aber habs grade getestet und habe keinen Fehler bekommen :gruebel:

Luckie 22. Jan 2007 14:22

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:
var
  i: Integer;
begin
  for i := 0 to self.Count - 1 do
    self.Items[i].Parent := nil;
  inherited;
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.

Angel4585 22. Jan 2007 14:36

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:

Luckie 22. Jan 2007 14:37

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.

Hawkeye219 22. Jan 2007 14:47

Re: TObjectList: AV wenn OwnsObject := True
 
Michael, wäre Delphi-Referenz durchsuchenTComponentList eine Alternative für dich?

Gruß Hawkeye

Luckie 22. Jan 2007 14:52

Re: TObjectList: AV wenn OwnsObject := True
 
Auch damit bekomme ich eine AV, auch wenn ich im Destruktor den parent auf nil setze:
Delphi-Quellcode:
self.Items[i].Parent := nil;
Das ist irgendwie alles nichts. Ich glaube, ich bleibe doch bei meiner TList. :?

Angel4585 22. Jan 2007 14:57

Re: TObjectList: AV wenn OwnsObject := True
 
Also ich hab jetzt spasseshalber mal alle Komponenten vom Formular hinzugefügt und das ganze freigegeben.. kein Fehler..

Die Muhkuh 22. Jan 2007 14:58

Re: TObjectList: AV wenn OwnsObject := True
 
Du musst das schon mit diesem TImageEnVect versuchen, alles andere hat keinen Sinn :roll:

Der_Unwissende 22. Jan 2007 15:13

Re: TObjectList: AV wenn OwnsObject := True
 
Zitat:

Zitat von Luckie
Auch damit bekomme ich eine AV, auch wenn ich im Destruktor den parent auf nil setze:
Delphi-Quellcode:
self.Items[i].Parent := nil;
Das ist irgendwie alles nichts. Ich glaube, ich bleibe doch bei meiner TList. :?

Du solltest auch tunlichst dem Parent mitteilen, dass sein Child nicht mehr gültig ist, nicht umgekehrt. Wenn Du control.Parent := Blubb verwendest, dann wird bei dieser Zuweisung Blubb.insertControl(control) aufgerufen, ist Blubb hier nil, nun ja, dann wird das natürlich nicht aufgerufen, aber der alte Parent bekommt davon so nichts mit. Deswegen solltest du removeControl (vom Parent aus) verwenden (denke die Methode heißt so, ist jetzt aber aus dem Kopf, lieber nochmal nachschauen!).

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:
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;
Ach ja, natürlich darfst Du dann auch nur TControl-Instanzen einfügen.

Angel4585 22. Jan 2007 15:17

Re: TObjectList: AV wenn OwnsObject := True
 
Zitat:

Zitat von Die Muhkuh
Du musst das schon mit diesem TImageEnVect versuchen, alles andere hat keinen Sinn :roll:

Hab ich jetz au gemacht, hab alles gemacht was Luckie da oben auch zugewiesen hat, kommt immernoch kein Fehler... :gruebel:

Edit: jetzt wo ich die Kompos schon hab kannst des ding au ma schicken oder?

Hawkeye219 22. Jan 2007 15:44

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