Einzelnen Beitrag anzeigen

peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
672 Beiträge
 
Delphi 11 Alexandria
 
#14

AW: Komponenten während der Laufzeit erstellen und löschen

  Alt 23. Apr 2019, 11:43
Könnt ihr den Fehler finden, weshalb die ListBox Items nicht geladen werden bzw. weshalb dieses leer bleibt?
Delphi-Quellcode:
var zahlen: array of TStrings;
...
//In einer Procedure die ausgeführt wird und welche funktioniert
zahlen[ComboBox1.ItemIndex-1] := ListBox1.Items;
...
procedure TForm1.Button5Click(Sender: TObject);
begin
  ListBox1.Items := zahlen[ComboBox1.ItemIndex-1];
end;
Finde ehrlich gesagt nicht den Fehler, länge des Arrays wurde gesetzt, etc.
Tja, das Problem liegt vermutlich in deinem (mangelnden) Verständnis, wie Objekte funktionieren. Objekte sind Referenz-Typen, wenn man ein Objekt einer Variablen (oder dem Element eines Arrays) zuweist wird dabei nicht der Inhalt des Objektes kopiert, sondern seine Referenz (Addresse).

var zahlen: array of TStrings; Ein SetLength(zahlen, N) liefert hier erstmal nur Speicherplatz für N Referenzen, die alle auf Nil gesetzt sind. Der Array enthält also keine Objekte.

Delphi-Quellcode:
//In einer Procedure die ausgeführt wird und welche funktioniert
zahlen[ComboBox1.ItemIndex-1] := ListBox1.Items;
...
Jetzt hast Du ein Element im Array, das eine Referenz auf das Items-Objekt der Listbox enthält. Der Eintrag zeigt also auf das selbe Objekt wie Listbox1.Items. Du hast also keine Kopie des Inhalts der Liste erstellt, wie Du vermutlich vor hattest.
Wenn Du jetzt den Inhalt der Listbox änderst verweist auch die Referenz in deinem Array auf die geänderte Liste.

Delphi-Quellcode:
procedure TForm1.Button5Click(Sender: TObject);
begin
  ListBox1.Items := zahlen[ComboBox1.ItemIndex-1];
end;
Und da wird es ganz übel. Die Zuweisung an die Items-Eigenschaft ruft die Setter-Funktion auf, und die löscht zunächst mal den Inhalt der Items-Liste. Dummerweise löscht sie damit auch den Inhalt der Liste in zahlen[ComboBox1.ItemIndex-1], denn das ist ja die selbe Liste...

Um wirklich den Inhalt der Listbox zu speichern mach das so:


Delphi-Quellcode:
var zahlen: array of String;

zahlen[ComboBox1.ItemIndex-1] := ListBox1.Items.Text;

ListBox1.Items.Text := zahlen[ComboBox1.ItemIndex-1];
Das ist am einfachsten, da der Compiler die Speicherverwaltung für Strings automatisch macht. Man könnte zwar auch TStringlist-Objekte als Ablage des Listeninhalts verwenden, aber das ist deutlich aufwendiger, den diese Objekte mußt Du erst erzeugen und im Array ablegen, Du mußt ihre Assign-Methode verwenden, um den Inhalt von Listbox1.Items in eine solche TStringlist zu kopieren, und natürlich mußt Du die Objekte wieder löschen, wenn Du sie nicht mehr brauchst. Wenn sich die Länge des Arrays ändern kann wird das aufwendig, da mußt Du höllisch aufpassen, damit keine Speicherlecks entstehen (wenn der Array schrumpft) oder TStringlist-Objekte fehlen (wenn der Array wächst, die neuen Elemente sind zunächst nil). In einem solchen Fall wäre eine TObjectlist (oder TObjectlist<TStringlist>) besser geeignet als ein array, die übernimmt zumindestens einen Teil der Speicherverwaltung.
Peter Below
  Mit Zitat antworten Zitat