Home » Tutorials » Third-Party-Komponenten » VirtualTreeView

VirtualTreeView

Speichern und Laden

Das Speichern und Laden des Baums gestaltet sich einfacher als man zuerst annehmen möchte. Es ist zwar etwas komplexer als es bei der TTreeView-Komponente der Fall war, aber dennoch lässt sich diese Aufgabe mit einigen Zeilen erledigen.

Der Baum stellt die Methoden SaveToFile und LoadFromFile zur Verfügung, die als Parameter nur den Dateinamen inkl. Pfad erwarten. Die Methoden speichern die Struktur und den Aufbau (inkl. Informationen, ob ein Node ausgeklappt ist) des Trees ab.

Speichern:

procedure TForm1.Button2Click(Sender: TObject);
begin
  vst.SaveToFile('C:VirtualTree1.dat');
end;

Laden:

procedure TForm1.Button3Click(Sender: TObject);
begin
  vst.LoadFromFile('C:VirtualTree1.dat');
end;

Meistens liegen aber noch weitere Daten vor, die jedem Node zugeordnet sind. Diese werde bei dem Aufruf der o.g. Methoden nicht mit gespeichert, bzw. geladen. Um das Speichern/Laden der einzelnen Node-Daten zu vereinfachen stellt der Baum zwei Ereignisse zur Verfügung: Das OnSaveNode- und das OnLoadNode-Ereignis:

procedure TForm1.vstSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
 Stream: TStream);

Die Ereignisse besitzen den gleichen Procedurekopf. Unter den Parametern Sender und Node solltest Du dir inzwischen etwas vorstellen können. Zum ersten Mal taucht der Parameter Stream auf. Dabei handelt es sich um den Stream, dem die Daten hinzugefügt werden. Da der Stream fortlaufend ist (d.h. es wird ein Node an den anderen gehängt), reicht es aus, die Daten einfach per Write in den Stream zu schreiben. Es muss sich weder um die Speicherreservierung, noch um die Freigabe des Streams gekümmert werden.

Nehmen wir an, unser Daten-Record hätte folgenden Aufbau:

type
  PTreeData = ^TTreeData;
  TTreeData = record
    TestStr: String
end;

Speichern

Um diese Daten zusätzlich abspeichern zu können, kann man so vorgehen (Ereignis: OnSaveNode):

procedure TForm1.vstSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
 Stream: TStream);
var
  Data: PTreeData;
  Len: integer;
begin
  Data := vst.GetNodeData(Node);
  Len := Length(Data.TestStr);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data.TestStr)^, Len);
end;

Per GetNodeData wird sich die Adresse der Daten geholt. In unserem Falle besteht der Record nur aus einem String. Da die Länge des Strings dynamisch ist, muss die aktuelle Länge ebenfalls gespeichert werden, da es sonst beim Laden zu Problemen kommt. Die Länge in Bytes wird in der Integer-Variable Len gespeichert und per Stream.Write in den Stream geschrieben. Danach folgt direkt der String. Dem ersten Parameter wird die Adresse des ersten Zeichens übergeben, danach folgt die Länge des Datentyps in Bytes. Die Länge/Größe von Datentypen wird meist mittels SizeOf (wie z.B. bei Integer-Typen) oder Length (wie hier beim String) ermittelt.

Würde dein Datenrecord einen Integer-Wert enthalten, würdest du ihn so abspeichern:

 Stream.Write(Data.IntegerVar, SizeOf(Data.IntegerVar));

Wenn du deinen Baum auf diese Weise abspeicherst, empfiehlt es sich die Eigenschaft TreeOptions.StringOptions so zu bearbeiten, dass der Wert ‚toSaveCaptions‘ nicht enthalten ist.

Laden

Das Laden der Struktur unterscheidet sich nur minimal vom Speichern. Wir befinden uns dieses Mal im OnLoadNode-Ereignis:

procedure TForm1.vstLoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
 Stream: TStream);
var
  Data: PTreeData;
  Len: integer;
begin
  Data := vst.GetNodeData(Node);
  Stream.read(Len, SizeOf(Len));
  SetLength(Data.TestStr, Len);
  Stream.read(PChar(Data.TestStr)^, Len);
end;

Zuerst holt man sich die Speicheradresse der Daten. Danach wird die Länge des Strings ausgelesen, die wir als Integer gespeichert haben. Über SetLength wird dem String genau die Größe im Speicher zugewiesen, die wir eben ermittelt haben. Zum Schluss erfolgt nur noch per Stream.Read der Lesevorgang unseres Strings. Als Parameter erwartet die Funktion die Startadresse des Strings (PChar( Data.TestStr)^) und die Länge (Len).

Achte darauf, dass du die einzelnen Daten genau in der gleichen Reihenfolge ausliest, wie du sie beim Speichern speicherst.

Nun sollte der Baum über die Methode SaveToFile den kompletten Baum inkl. Daten speichern und mit LoadFromFile wieder komplett laden.

Ein Beispiel zu diesem Kapitel kannst du hier downloaden. Das Beispiel basiert auf den mitgelieferten Demos des VirtualTree-Archivs.