Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Fehler beim freigeben dynamisch erzeugter TLabels (https://www.delphipraxis.net/94393-fehler-beim-freigeben-dynamisch-erzeugter-tlabels.html)

hugo1990 20. Jun 2007 20:59


Fehler beim freigeben dynamisch erzeugter TLabels
 
Ich habe ein Problem und zwar wenn ich folgende TLabels
Delphi-Quellcode:
Bilderupname:array of TLabel;
die ich so
Delphi-Quellcode:
SetLength(Bilderupname,Files.Count-2);
for i:=1 to Files.Count-2 do
  begin
  Bilderupname[i-1]:=TLabel.Create(Form1);
  Bilderupname[i-1].Caption:=IntToStr(i)+'.jpg';
  Bilderupname[i-1].AutoSize:=True;
  ...
  end;
erzeugt habe so
Delphi-Quellcode:
for i:=0 to high(Bilderupname) do
  begin
  Bilderupname[i].Free;
  end;
wieder freigeben möchte kommt die Fehlermeldung "Zugriffsverletzung bei Adresse ... in Modul '...'. Lesen von Adresse ...". Das kuriose ist, es geschieht nur beim freigeben des letzten TLabels und das ganze mache ich auch noch mit TImages, da tritt der Fehler nicht auf. Kann mir jemand Helfen?

mkinzler 20. Jun 2007 21:01

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Du verwendest beim Erzeugen auch andere Grenzen als beim Freigeben.
BTW Ersetzte Form1 besser durch Self

dataspider 20. Jun 2007 21:06

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Der sichere Weg:
Delphi-Quellcode:
for i := Low(Bilderupname) to high(Bilderupname) do
  Bilderupname[i].Free;
Frank

hugo1990 20. Jun 2007 21:10

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Also die Grenzen kommen im Endeffekt wieder auf das selbe, daran liegt es nicht und auch mit Self statt Form1 geht es nicht.
Auch das mit dem low geht nicht, aber der fehler tritt ja auch nicht beim ersten sondern beim letzten auf, da der Fehler, wenn ich die obere Grenze auf high(Bilderupname)-1 setzte, nicht kommt. nur ist dann das letzte Label noch da.

Edit: Ok der Fehler muss wo anders liegen, den wenn ich die TLabels zuerst freigeben, dann tritt der Fehler bei den TImages auf.

DeddyH 20. Jun 2007 21:15

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Ich habe mir angewöhnt, das Freigeben immer in umgekehrter Reihenfolge zu erledigen, da ich sonst auch des Öfteren AV geerntet habe.
Delphi-Quellcode:
for i := high(Bilderupname) downto Low(Bilderupname) do
  Bilderupname[i].Free;

Helmi 20. Jun 2007 21:16

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
dreh doch den ganzen Spass mal um:

Delphi-Quellcode:
for i := High(Bilderupname) downto Low(Bilderupname) do
  Bilderupname[i].Free;

DeddyH 20. Jun 2007 21:17

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
*Hehe* eine Minute schneller :mrgreen: :cheers:

hugo1990 20. Jun 2007 21:19

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
umdrehen hat auch nichts gebracht.

dataspider 20. Jun 2007 21:20

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Du versuchst aber nicht, das Freigeben im Destructor oder so zu machen. Das kann nämlich auch schiefgehen.

Frank

DeddyH 20. Jun 2007 21:22

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Was ist eigentlich Files?

Hawkeye219 20. Jun 2007 21:23

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Hallo,

noch eine Möglichkeit: wird der Parent des Labels freigegeben, bevor du versuchst, die Labels manuell freizugeben? TWinControls zerstören im Destruktor auch ihre Child-Controls.

Gruß Hawkeye

Jelly 20. Jun 2007 21:34

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Und wieder ein Beispiel für TObjectList... Da brauchts kein Array, und das Freigeben (bzw. ein Clear) der Liste gibt dessen Objekte gleich mit frei.

Helmi 20. Jun 2007 21:39

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

anbei ein Beispiel-Programm das Labels erzeugt und wieder löscht

wie du siehst sind die for-Schleifen etwas anders

Hawkeye219 20. Jun 2007 21:52

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Zitat:

Zitat von Jelly
Und wieder ein Beispiel für TObjectList... Da brauchts kein Array, und das Freigeben (bzw. ein Clear) der Liste gibt dessen Objekte gleich mit frei.

Ich stimme dir fast zu, ich würde allerdings eine Delphi-Referenz durchsuchenTComponentList wählen. Damit wären dann auch die Zugriffsverletzungen weg - falls sie so verursacht werden, wie ich es vermute.

Gruß Hawkeye

Jelly 20. Jun 2007 21:57

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
TComponentList ist in dem Fall wohl wirklich die noch bessere Wahl. Kannt ich gar nicht vorher :zwinker:

Chemiker 20. Jun 2007 22:39

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Hallo hugo1990,

Vielleicht hilft Dir das weiter:

Ersetze:
Delphi-Quellcode:
for i:=1 to Files.Count-2 do

durch:
Delphi-Quellcode:
for i:=0 to Files.Count-1 do

Bis bald Chemiker

hugo1990 21. Jun 2007 15:03

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Wie funktioniert den das mit der TComponentList genau?

Helmi 21. Jun 2007 15:06

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
hat sich denn niemand mein Beispiel angeschaut? *böse guck*

hugo1990 21. Jun 2007 15:09

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
@Helmi
Ich habe mir dein Beispiel angeguckt, aber wenn ich das so in mein programm schreibe tritt der Fehler trotzdem auf.

Helmi 21. Jun 2007 15:12

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
sicher?
hast es komplett so übernommen von mir?

hoika 21. Jun 2007 15:19

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Hallo,

Poste noch mal die Erzeugung und Freigabe


Heiko

hugo1990 21. Jun 2007 15:28

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
@ helmi
jop, das einzige was anders ist, ist das Parent

@ hoika
Erzeugung:
Delphi-Quellcode:
SetLength(Bilderup,Files.Count-2);
SetLength(Bilderupname,Files.Count-2);
for i:=low(Bilderup) to high(Bilderup) do
  begin
  {x,y festlegen}
  Bilderup[i]:=TImage.Create(Form1);
  Bilderup[i].Picture.LoadFromFile(...);
  Bilderup[i].Left:=x;
  Bilderup[i].Top:=y;
  Bilderup[i].Width:=133;
  Bilderup[i].Height:=100;
  Bilderup[i].Parent:=PicsAtServer;
  Bilderup[i].Center:=True;
  Bilderupname[i]:=TLabel.Create(Form1);
  Bilderupname[i].Caption:=IntToStr(i+1)+'.jpg';
  Bilderupname[i].AutoSize:=True;
  Bilderupname[i].Left:=x+(133-Bilderupname[i].Width) div 2;
  Bilderupname[i].Top:=y+103;
  Bilderupname[i].Parent:=PicsAtServer;
  end;
PicsAtServer ist eine TScrollBox;

Freigabe:
Delphi-Quellcode:
for i:=high(Bilderup) downto low(Bilderup) do
  begin
  FreeAndNil(Bilderup[i]);
  end;
for i:=high(Bilderupname) downto low(Bilderupname) do
  begin
  FreeAndNil(Bilderupname[i]);
  end;

hugo1990 21. Jun 2007 16:09

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Ok ich habe jetzt rausgefunden, wie das mit der TComponentList geht, aber der Fehler kommt immer noch.

Delphi-Quellcode:
for i:=0 to Anzahl-1 do
  begin
  {x,y festlegen}
  Bilderup.Add(TImage.Create(Form1));
  with (Bilderup.Items[i] as TImage) do
    begin
    Picture.LoadFromFile(...);
    Left:=x;
    Top:=y;
    Width:=133;
    Height:=100;
    Parent:=PicsAtServer;
    Center:=True;
    end;
  Bilderupname.Add(TLabel.Create(Form1));
  with (Bilderupname.Items[i] as TLabel) do
    begin
    Caption:=IntToStr(i+1)+'.jpg';
    AutoSize:=True;
    Left:=x+(133-Width) div 2;
    Top:=y+103;
    Parent:=PicsAtServer;
    end;
  end;
So erzeuge ich jetzt die Images und Labels und dann zum freigeben
Delphi-Quellcode:
Bilderup.Clear;
Bilderupname.Clear;
Oder mache ich da was falsch?

Edit: Ich glaube ich werde mein Programm noch einmal von vorn anfangen, den wenn ich den Code zum erzeugen und freigeben in ein anderes Programm packe geht es, also werde ich irgendwo einen anderen Fehler haben.

Sidorion 21. Jun 2007 16:14

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Zitat:

TWinControls zerstören im Destruktor auch ihre Child-Controls.
Na das ist mal wieder ein klassischer Fall von fundiertem Halbwissen. Components zerstören ihre 'child' Components (also alle, deren Owner-Property auf das zerstörte Component weist). Die Control-Hierarchie hat nur was mit Parents zu tun, nicht mit Besitzrechten.

Da die Labels und Images mit der Form als Owner erstellt wurden müssen sie überhaupt nicht manuell freigegeben werden (ausser die Freigabe findet ausserhalb des Formulardestruktors statt). Allerhöchstens muss das Array mit Nilen gefüllt werden.

hoika 21. Jun 2007 16:39

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Hallo,

mit TLabel.Create(NIL) wird das Label nicht in die
Komponents-Liste des Forms eingetragen.


Heiko

hugo1990 21. Jun 2007 17:18

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
komisch ich habe jetzt das ganze nochmal neu gemacht also neue Anwendung und dann jede Procedure erstellt und rüber kopiert und jetzt geht es, der Fehler tritt nicht mehr auf.

Hawkeye219 21. Jun 2007 17:55

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Hallo Sidorion,

Zitat:

Na das ist mal wieder ein klassischer Fall von fundiertem Halbwissen.
...oder einer falsche Einschätzung deinerseits aufgrund meiner unglücklichen Formulierung. Hätte ich von "untergeordneten Controls" statt "Child-Controls" gesprochen, wäre hoffentlich klar gewesen, worauf ich hinaus wollte:

Zitat:

Zitat von TWinControl.Destroy
Delphi-Quellcode:
[...]
I := ControlCount;
while I <> 0 do
begin
  Instance := Controls[I - 1];
  Remove(Instance);
  Instance.Destroy; // <---
  I := ControlCount;
end;

Ich hegte den Verdacht, daß der Parent (nicht Owner!) der Labels vorzeitig freigegeben wird und damit seine untergeordneten(!) Controls ebenfalls vernichtet. Dies hätte im dynamischen Array ungültige Referenzen hinterlassen. Der Versuch, über diese Referenzen eine erneute Freigabe mittels Free durchzuführen, hätte dann zu einer Schutzverletzung geführt.

Gruß Hawkeye

Sidorion 22. Jun 2007 09:03

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Nach Deinem ersten Post hätte ich die Fehlinterpretation meinerseits durchaus eingestanden, aber Dein zweiter Post beweist meine Annahme als richtig.
Wird ein COMPONENT zerstört, trägt es sich selbsttätig aus der Components-Liste seines Owners aus und zerstört seine eigenen Components mit(vor seiner eigenen Vernichtung).
Ist Ein Component obendrein noch ein CONTROL, so trägt es sich aus der Controls-Liste seines PARENTS aus und schreibt in die Parent-Eigenschaft aller seiner Controls ein Nil. Da wird nix vernichtet.

Die Component-Hierarchie ist eine Besitzanzeigende, die Control-Hierarchie eine Lagebeschreibende. Das einzige was da passieren kann, ist dass die Untergeordneten unsichtbar werden, da der Parent flöten geht. Zudem können sich diese beiden Hierarchien stark unterscheiden. In einem über Designer generierten Formular, ist immer die Form der Owner von allen Components, die Parents können sich aber stark unterscheiden (z.B. PageControl).

Nichtsdestotrotz hast Du mit dem Verdacht der ungültigen Referenzen im Array völlig recht.

Hawkeye219 22. Jun 2007 09:50

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Zitat:

Zitat von Sidorion
Ist Ein Component obendrein noch ein CONTROL, so trägt es sich aus der Controls-Liste seines PARENTS aus und schreibt in die Parent-Eigenschaft aller seiner Controls ein Nil.

Soweit richtig, das passiert in Remove (Instance).

Zitat:

Da wird nix vernichtet.
Nun wird's meiner Meinung nach falsch. Der Befehl zur Vernichtung (Instance.Destroy) folgt direkt auf den zum Austragen, siehe Beitrag #27.

Hier ein kleiner Codeauszug zum Testen:

Delphi-Quellcode:
interface

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Edit1: TEdit;
    btnKillPanel: TButton;
    btnKillEdit: TButton;
    procedure btnKillEditClick(Sender: TObject);
    procedure btnKillPanelClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    EditReference : TEdit;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnKillPanelClick(Sender: TObject);
begin
  Panel1.Free;
end;

procedure TForm1.btnKillEditClick(Sender: TObject);
begin
  EditReference.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  EditReference := Edit1;
end;
Wir haben ein Panel, auf diesem Panel liegt ein Edit-Control (Edit1.Owner = Form1, Edit1.Parent = Panel1). Mit btnKillPanel wird nun das Panel zerstört. Kurz vor seinem Tod zerstört es das auf ihm liegende Edit-Control. Dies geschieht im Destruktor von TWinControl, wie du leicht durch Einbindung der Debug-DCUs nachvollziehen kannst. Die private Referenz EditReference ist nun ungültig, ein anschließender Druck auf btnKillEdit führt zur Access Violation.

Diese kleine Simulation zeigt eine Möglichkeit auf, wie der Fehler im Programm von hugo1990 entstehen kann. EditReference entspricht dem dynamischen Array, btnKillEditClick steht für die manuelle Freigabe. Nun wäre nur noch das Gegenstück zu btnKillPanelClick in seinem Code aufzuspüren. Aber scheinbar ist Hugos Problem ja keines mehr...

Gruß Hawkeye

Sidorion 22. Jun 2007 11:32

Re: Fehler beim freigeben dynamisch erzeugter TLabels
 
Bei Gott Du hast Recht :shock: Wie kommen Die denn auf DAS schmale Brett????
Was passiert denn dann bei sowas:
Delphi-Quellcode:
  [..]
   TestEdit:=TEdit.Create(Form1);
   TestPanel:=TPanel.Create(TestEdit);
   TestPanel.Parent:=Self;
   TestEdit.Parent:=TestPanel;
   TestPanel.Free;
  [..]
Das Edit ist control vom Panel und das Panel component vom Edit. Beide geben sich gegenseitig frei, da musses doch Krachen!


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz