OOP5: Stringlisten, Listen und andere Behälter

Während man unter TP7 noch mühsam verzeigerte Listen selber konstruieren musste, gibt es Listen unter Delphi als vorgefertigte Objektklasse. Eine Listbox z.B. ist ein Ein- und Ausgabemedium für den Inhalt eines sog. Stringliste, d.h., neben der Funktion als Datenbehälter (in diesem Fall für Daten des Typs string) existieren verschiedene Methoden zur Manipulation des Inhaltes der zugehörigen Stringliste. Wie diese Methoden im einzelnen implementiert sind, bleibt das Geheimnis der Programmierer von Delphi, für den Benutzer sind nur die Aufrufe der Methoden veröffentlicht.

Die zu einer Listbox gehörenden Stringliste ist als Eigenschaft dieser Listbox : Listbox.Items implementiert. Sie wird automatisch mit der Instanziierung einer Listbox geschaffen, d.h. der Aufruf der Prozedur Create wird unter der Hand bereits ausgeführt, sobald man eine Listbox auf ein Formular setzt. Wichtige Methoden dieser Stringliste werden in dem Programm listen1.pas demonstriert.

function TForm1.Empty : Boolean;
begin
  result := ListBox1.Items.count = 0;
end;

procedure TForm1.NewBottomBtnClick(Sender: TObject);
begin
 
ListBox1.Items.Add('Eintrag '+IntToStr(zaehler));
  inc(zaehler);
end;

procedure TForm1.NewTopBtnClick(Sender: TObject);
begin
 
ListBox1.Items.Insert(0,'Eintrag '+IntToStr(zaehler));
  inc(zaehler);
end;

procedure TForm1.DeleteBottomBtnClick(Sender: TObject);
begin
if not empty then ListBox1.Items.Delete(ListBox1.Items.Count-1);
end;

procedure TForm1.DeleteTopBtnClick(Sender: TObject);
begin
if not empty then ListBox1.Items.Delete(0);
end;

procedure TForm1.SaveToFileBtnClick(Sender: TObject);
begin
ListBox1.Items.SaveToFile('otto.txt');
end;

procedure TForm1.LoadFromFileBtnClick(Sender: TObject);
begin
ListBox1.Items.LoadFromFile('otto.txt');
zaehler := ListBox1.Items.Count;
end;

end.

Interessant sind vor allem die einfachen Methoden den Inhalt einer Stringliste in eine Datei zu schreiben oder von einer Datei zu laden. Die Datei ist dann allerdings eineTextdatei, d.h. file of string, in der jeder Dateieintrag von dem anderen durch #13#10 getrennt wird. An dieser Stelle zeigen sich aber auch die Grenzen der StringListen: Sie sind offensichtlich nur für den Datentyp string geeignet, für Bytes würde man eine ByteListe, für Felder eine ArrayListe benötigen usw. Man sieht also, dass man noch einen Listentyp benötigt, der sehr viel allgemeiner zu benutzen ist als die StringListe. Dieser allgemeine Listentyp stellt eine Liste von Zeigern (pointer) auf zu speichernde Daten dar.

Als zu speichernder DatenTyp soll ein record (z.B. Personendaten) verwendet werden:

type

Tdaten = record
           Name, vname : string[20]
           Alter : integer;
         end;


Pdaten = ^Tdaten;

var
DatenListe : TList;

Zunächst muss man die Instanz DatenListe erstellen. Das geschieht an entsprechender Stelle durch die Zuweisung: DatenListe := Tlist.Create; In der folgenden Prozedur wird dynamisch ein Zeiger auf einen neuen Datensatz geschaffen und die verschiedenen Datenfelder mit den entsprechenden Inhalten versehen:

procedure AddEintrag(d : Tdaten);
var dptr : PDaten;
begin
  new(dptr);
  dptr^.name := d.name; dptr^.vname := d.vname; dptr^.alter := d.alter;
  DatenListe1.Add(dptr);
end;

Eine entsprechende Prozedur liest den Inhalt eines Listeneintrages wieder aus:

procedure GetEintrag(z : integer; var d: Tdaten);
var dptr : PDaten;
begin
  dptr := DatenListe.Items[z];
  d := dptr^;
end;

Entsprechend kann man natürlich auch eine Funktion verwenden, um den entsprechenden Datensatz auszulesen:


function GetEintrag(n: integer) : TDaten;
var dptr : PDaten;
begin
  dptr := DatenListe1.Items[n];
  result := dptr^;
end;

In beiden Fällen ist es notwendig, den zunächst untypisierten Zeiger DatenListe.Items[n] unzuwandeln in einen typisierten vom Typ Tdaten. Dieser Zeiger wird dann dereferenziert und sein Inhalt der Variablen d bzw. dem Funktionsrückgabewert zugewiesen.

Löschen, Einfügen usw. von Einträgen geschieht mit analogen Anweisungen wie bei der Stringliste. Verständlicherweise kann es keine Methode SaveToFile und LoadFromFile geben, da der Datentyp, der abgespeichert werden soll, für jede Liste verschieden sein kann. Deswegen muß man sich zunächst eine Instanz DatenFile : file of Tdaten schaffen, in die mit den üblichen Anweisungen Daten geschrieben, bzw. aus der man Daten auslesen kann. In dem beigefügten Programm adt2.dpr kann man zunächst mehrere Datensätze aus der Datei otto.dta auslesen, die dann in einem StringGrid ausgegeben werden.

Aufgaben:

Mit Hilfe der beiden Schalter >> und << sollen Einträge aus der einen Liste in eine zweite Liste und umgekehrt übertragen werden, d.h. der Eintrag soll in DatenListe1 gelöscht und in DatenListe2 eingefügt werden (wo auch immer). Entsprechend sollen auch die Ausgaben in den StringGrids aktualisiert werden. Anschließend kann der Inhalt beider Listen wieder auf die Festplatte geschrieben werden. Wer damit fertig ist, kann ja mal das Verschieben mittels Drag und Drop versuchen !?

(Lösung: liste2.pas)

Zurück zu Delphi

© Dietrich Praclik