Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Probleme mit TList (https://www.delphipraxis.net/79382-probleme-mit-tlist.html)

stevewilson 21. Okt 2006 13:42


Probleme mit TList
 
Hallo,

bin momentan beim Entwickeln eines Musik-CD-Verwaltungsystems unter Delphi.
Ich verwende dabei bewusst(!) keine Datenbankkomponenten, sondern speichere die CDs in eine TList, die ich dann später in eine Datei schreiben will. Ich habe aber schon Probleme beim Aufruf von:

Delphi-Quellcode:
cdList.add(cd)
ist die Liste leer, das kann ich sehr gut im Debugger am Eintrag () sehen, wobei ich beim Zufügen von 2 Elementen auf die Indizes 0 und 1 zugreifen kann, mir der spätere Aufruf von:

Delphi-Quellcode:
cd := cdList[0];
oder auch:

Delphi-Quellcode:
Code:
cd := TCD(cdList[1]);
aber nichts neues zurückliefert, sondern das beibehalten wird, was vorher in "cd" drin stand.

Hier der gesamte Quellcode:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, Grids, StdCtrls, Contnrs;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Datei1: TMenuItem;
    Beenden1: TMenuItem;
    Hilfe1: TMenuItem;
    Info1: TMenuItem;
    ListBox1: TListBox;
    StringGrid1: TStringGrid;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    Edit4: TEdit;
    Label4: TLabel;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Speichern1: TMenuItem;
    Speichernals1: TMenuItem;
    Beenden2: TMenuItem;
    Neu1: TMenuItem;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    Button8: TButton;
    procedure Info1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Beenden2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TCd = class(TObject)
    interpreter : string;
    albumTitle : string;
    genre      : string;
    songTitles : TStringList;
  private
    procedure setValues(interpreter, albumTitle, genre : string);
    procedure addTitel(songTitles : TStringList);
end;

var
  cd    : TCd;
  cdList : TList;

procedure TForm1.Info1Click(Sender: TObject);
begin
  //messageBox();
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  //Zeilen benennen
  with stringGrid1 do
  begin
    colWidths[0] := 30; //Breite der fixen Nr-Spalte verringern
    cells[0, 0] := 'Nr.';
    cells[1, 0] := 'Interpret';
    cells[2, 0] := 'Albumtitel';
    cells[3, 0] := 'Genre';
    options := [goFixedVertLine, goFixedHorzLine, goHorzLine,
                goVertLine, goColSizing];
    //goColSizing = Spaltenbreite einstellbar
    //goVertLine/goHorzLine = Gitternetz-Linien erscheinen
  end;
  cdList := TList.create; //richtig?
  cd := TCD.create;
end;


procedure TForm1.Button5Click(Sender: TObject);
begin
  close;
end;

//Zum Bearbeiten und Erstellen einer CD
procedure TCd.setValues(interpreter, albumTitle, genre : string);
begin
  cd.interpreter := interpreter;
  cd.albumTitle := albumTitle;
  cd.genre := genre;
end;

//Zum Hinzufügen von Titeln zur aktuellen CD
procedure TCd.addTitel(songTitles : TStringList);
begin
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  cd.free;
  cdList.free;
end;

//Button "CD hinzufuegen"
procedure TForm1.Button1Click(Sender: TObject);
var s : TStringList;
begin
  cd.setValues(edit1.text, edit2.text, edit3.text);
{  s.create;
  s.add('a');
  cd.songTitles := s;}
  cdList.add(cd); //funktioniert nicht??
  stringGrid1.cells[1, 1] := cd.interpreter;
  stringGrid1.cells[2, 1] := cd.albumTitle;
  stringGrid1.cells[3, 1] := cd.genre;
  edit1.text := intToStr(stringGrid1.rowCount);

end;

procedure TForm1.Beenden2Click(Sender: TObject);
begin
  close;
end;


procedure TForm1.Button8Click(Sender: TObject);
begin
  cd := cdList[0]; //geht nicht??
  stringGrid1.cells[1, 3] := cd.interpreter;
  stringGrid1.cells[2, 3] := cd.albumTitle;
  stringGrid1.cells[3, 3] := cd.genre;
  cd := TCD(cdList[1]); //geht auch nicht??
  stringGrid1.cells[1, 4] := cd.interpreter;
  stringGrid1.cells[2, 4] := cd.albumTitle;
  stringGrid1.cells[3, 4] := cd.genre;

end;


end.

Kinimod8 21. Okt 2006 14:16

Re: Probleme mit TList
 
Schau' dir vieleicht erst mal das TList-Tutorial der DSDT an.

stevewilson 21. Okt 2006 15:29

Re: Probleme mit TList
 
Hallo,

sorry, aber das hilft mir nicht weiter, jetzt ich aus CD einen pointer gemacht, mit:

Delphi-Quellcode:
var
  cd    : ^TCd;
Aber das hier wirft auch wieder ne Invalidpointer-Exception:

Delphi-Quellcode:
cdList.add(cd);
Das muss doch sowieso ohne Pointer gehen, die TList verwendet doch schon nen Pointerarray
in seiner inneren Struktur.

Wobei, die add-methode ja schon nen Pointer will...
Aus dem Tutorium werde ich nicht schlauer...

Hador 21. Okt 2006 15:31

Re: Probleme mit TList
 
Arbeite doch einfach mit der TObjectList aus der Unit Contnrs.
Oder mit der von meiner Homepage :wink:

stevewilson 21. Okt 2006 15:54

Re: Probleme mit TList
 
Ja, schön,

hätte ich ja gerne gemacht. aber dann schreibt er in cdList wieder nix rein,
der fehler muss irgendwo in der "procedure TForm1.Button1Click(Sender: TObject)" sein.

guckt euch das mal an:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, Grids, StdCtrls, Contnrs;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Datei1: TMenuItem;
    Beenden1: TMenuItem;
    Hilfe1: TMenuItem;
    Info1: TMenuItem;
    ListBox1: TListBox;
    StringGrid1: TStringGrid;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    Edit4: TEdit;
    Label4: TLabel;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Speichern1: TMenuItem;
    Speichernals1: TMenuItem;
    Beenden2: TMenuItem;
    Neu1: TMenuItem;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    Button8: TButton;
    procedure Info1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Beenden2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TCd = class(TObject)
    interpreter : string;
    albumTitle : string;
    genre      : string;
    songTitles : TStringList;
  private
    procedure setValues(interpreter, albumTitle, genre : string);
    procedure addTitel(songTitles : TStringList);
end;

var
  cd    : TCd;
  cdList : TObjectList;

procedure TForm1.Info1Click(Sender: TObject);
begin
  //messageBox();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Zeilen benennen
  with stringGrid1 do
  begin
    colWidths[0] := 30; //Breite der fixen Nr-Spalte verringern
    cells[0, 0] := 'Nr.';
    cells[1, 0] := 'Interpret';
    cells[2, 0] := 'Albumtitel';
    cells[3, 0] := 'Genre';
    options := [goFixedVertLine, goFixedHorzLine, goHorzLine,
                goVertLine, goColSizing];
    //goColSizing = Spaltenbreite einstellbar
    //goVertLine/goHorzLine = Gitternetz-Linien erscheinen
  end;
  cdList := TObjectList.create; //richtig?
  cd := TCD.create;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  close;
end;

//Zum Bearbeiten und Erstellen einer CD
procedure TCd.setValues(interpreter, albumTitle, genre : string);
begin
  cd.interpreter := interpreter;
  cd.albumTitle := albumTitle;
  cd.genre := genre;
end;

//Zum Hinzufügen von Titeln zur aktuellen CD
procedure TCd.addTitel(songTitles : TStringList);
begin
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  cd.free;
  cdList.free;
end;

//Button "CD hinzufuegen"
procedure TForm1.Button1Click(Sender: TObject);
var s : TStringList;
begin
  cd.setValues(edit1.text, edit2.text, edit3.text);
{  s.create;
  s.add('a');
  cd.songTitles := s;}
  cdList.add(cd); //funktioniert nicht??
  stringGrid1.cells[1, 1] := cd.interpreter;
  stringGrid1.cells[2, 1] := cd.albumTitle;
  stringGrid1.cells[3, 1] := cd.genre;
  edit1.text := intToStr(stringGrid1.rowCount);
end;

procedure TForm1.Beenden2Click(Sender: TObject);
begin
  close;
end;

procedure TForm1.Button8Click(Sender: TObject);
begin
  cd := TCD(cdList[0]); //geht nicht??
  stringGrid1.cells[1, 3] := cd.interpreter;
  stringGrid1.cells[2, 3] := cd.albumTitle;
  stringGrid1.cells[3, 3] := cd.genre;
  cd := TCD(cdList[1]); //geht auch nicht??
  stringGrid1.cells[1, 4] := cd.interpreter;
  stringGrid1.cells[2, 4] := cd.albumTitle;
  stringGrid1.cells[3, 4] := cd.genre;
end;

end.

Muetze1 21. Okt 2006 16:14

Re: Probleme mit TList
 
Dein Problem liegt einfach nur darin, dass du nur eine Instanz für den Eintrag (cd) anlegst. Wenn du nur eine Instanz hast, liegt in TList auch in beiden Einträgen die selbe Instanz. Somit überschreibst du dir selber die Daten beim zuweisen. Du brauchst pro Eintrag eine eigene Instanz der Klasse TCd.

stevewilson 21. Okt 2006 16:18

Re: Probleme mit TList
 
Hallo,

ist das denn dann richtg? Irgendwie bekomme ich jetzt eine EAccesViolation


Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var s : TStringList;
begin
  cd := TCD.create;
  cd.setValues(edit1.text, edit2.text, edit3.text);
{  s.create;
  s.add('a');
  cd.songTitles := s; }
  cdList.add(cd); //funktioniert nicht??
  stringGrid1.cells[1, 1] := cd.interpreter;
  stringGrid1.cells[2, 1] := cd.albumTitle;
  stringGrid1.cells[3, 1] := cd.genre;
  edit1.text := intToStr(stringGrid1.rowCount);
  cd.free;
end;

stevewilson 21. Okt 2006 16:22

Re: Probleme mit TList
 
Hab jetzt diesen Teil auch angepasst:

Delphi-Quellcode:
procedure TForm1.Button8Click(Sender: TObject);
begin
  cd := TCD.create;
  cd := TCD(cdList[0]); //geht nicht??
  stringGrid1.cells[1, 3] := cd.interpreter;
  stringGrid1.cells[2, 3] := cd.albumTitle;
  stringGrid1.cells[3, 3] := cd.genre;
  cd.free;
  cd := TCD.create;
  cd := TCD(cdList[1]); //geht auch nicht??
  stringGrid1.cells[1, 4] := cd.interpreter;
  stringGrid1.cells[2, 4] := cd.albumTitle;
  stringGrid1.cells[3, 4] := cd.genre;
  cd.free;
end;
aber jetzt schreibt er nichts mehr in die Stringgrid.

Muetze1 21. Okt 2006 16:26

Re: Probleme mit TList
 
Mal eine Frage zu diesem Code:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var s : TStringList;
begin
  cd := TCD.create;
  cd.setValues(edit1.text, edit2.text, edit3.text);
{  s.create;
  s.add('a');
  cd.songTitles := s; }
  cdList.add(cd); //funktioniert nicht??
  stringGrid1.cells[1, 1] := cd.interpreter;
  stringGrid1.cells[2, 1] := cd.albumTitle;
  stringGrid1.cells[3, 1] := cd.genre;
  edit1.text := intToStr(stringGrid1.rowCount);
  cd.free;
end;
Wenn du oben die Instanz anlegst und der Liste hinzufügst, aber unten mit cd.Free die Instanz wieder freigibst - was meinst du denn, liegt in der Liste drinne?

Richtig - ein Verweis auf die Instanz die nicht mehr existiert, da du diese ja mit Free schon freigegeben hast. Somit kannst du schlecht nochmal irgendwas aus der Liste wieder rausholen...

stevewilson 21. Okt 2006 16:34

Re: Probleme mit TList
 
Ja, das dachte ich mir schon. Aber wie kriege ich das dann hin, ohne einen Array für "cd" zu verwenden?
es muss doch irgendwie möglich sein, ohne pointer bzw. dynamische arrays zu verwenden, ich wollte streng objektorientiert programmieren...

stevewilson 21. Okt 2006 16:36

Re: Probleme mit TList
 
Dabei muss ich das mit TList oder TObjectList realisieren. Welches von beiden ich verwende, ist mir freigestellt,
allerdings ist Vorgegeben, auf jeden Fall eines von beiden zu benutzen.

Muetze1 21. Okt 2006 16:38

Re: Probleme mit TList
 
Zitat:

Zitat von stevewilson
Ja, das dachte ich mir schon. Aber wie kriege ich das dann hin, ohne einen Array für "cd" zu verwenden?
es muss doch irgendwie möglich sein, ohne pointer bzw. dynamische arrays zu verwenden, ich wollte streng objektorientiert programmieren...

1. Einfach das cd.free entfernen und es sollte laufen. Die Instanz brauchst du doch so lange sie in der Liste ist. Daher: freigeben, wenn du sie aus der Liste entfernst. Und dafür schau dir mal Punkt 2 an
2. Es wurde schon in diesem Thread darauf hingewiesen, dass du die Klasse TObjectList anstatt TList verwenden solltest, da diese Klasse dir alles für Instanzen in einer Liste zur Verfügung stellt und auch die Möglichkeit diese Instanzen beim entfernen aus der Liste mit frei zu geben.
3. Jede Instanz ist im Inneren ein Pointer, Delphi versteckt dies aber nach aussen. Daher arbeitest du so oder so mit Pointern. Deshalb zeigt deine Variable cd und der Eintrag in der Liste (beides sind Zeiger) auf die gleiche Stelle im RAM (bei dem Code zuvor). Dadurch haben auch beide Listeneinträge die gleichen Daten gehabt (beide zeigten auf ein und die selbe Instanz).

stevewilson 21. Okt 2006 16:44

Re: Probleme mit TList
 
Ach ja, richtig.

Wenn ich einem Objekt einer Klasse neue Werte zuweise, dann wird das Objekt an eine Andere adresse kopiert, quasi dupliziert?

Und wegen "cd.free"-aufrufes hatte ich auch bei der TObjectList einen Fehler oder? Da cdList.free schon alle Instanzen löscht, wie du sagst.

Vielen Dank für die Hilfe!

Muetze1 21. Okt 2006 17:01

Re: Probleme mit TList
 
Zitat:

Zitat von stevewilson
Wenn ich einem Objekt einer Klasse neue Werte zuweise, dann wird das Objekt an eine Andere adresse kopiert, quasi dupliziert?

Nein, sowas findest du in C++ und C# mit automatischen Instanzen, nicht bei uns. Das Objekt wird nicht kopiert oder weg bewegt.

Zitat:

Zitat von stevewilson
Und wegen "cd.free"-aufrufes hatte ich auch bei der TObjectList einen Fehler oder? Da cdList.free schon alle Instanzen löscht, wie du sagst.

Naja, nicht ganz. cdList.Free will alle seine Elemente freigeben, aber er hat nur tote, schon freigegebene, Instanzen in seiner Liste und stürzt beim Versuch das ganze nochmals freizugeben ab.

stevewilson 21. Okt 2006 17:08

Re: Probleme mit TList
 
und bei java findet man sowas auch, zumindest bei den String-Objekten

Naja, jetzt hab ich jedenfalls alles verstanden :D

Danke.

Khabarakh 21. Okt 2006 17:58

Re: Probleme mit TList
 
Zitat:

Zitat von stevewilson
und bei java findet man sowas auch, zumindest bei den String-Objekten

In gewisser Weise findest du das auch bei Delphi. Bei der Zuweisung einer String-Variablen an eine andere wird zwar nur ein Zeiger kopiert, wird aber eine Referenz verändert, bleibt die andere unberührt; der String wurde also vor der Manipulation kopiert.


Zitat:

Zitat von Muetze1
Nein, sowas findest du in C++ und C# [...]

Nana. In C++ mag sowas funktionieren, aber die andere Sprache stammt immerhin von Herrn Hejlsberg ;) .


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:57 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