Home » Tutorials » Third-Party-Komponenten » VirtualTreeView

VirtualTreeView

Den Nodes Daten hinzufügen

Bisher war das Hinzufügen von Nodes usw. recht einfach. Ab hier wird es evtl. etwas komplizierter. Wir fügen nämlich jetzt nicht nur einfach ein Node hinzu sondern zusätzlich auch noch Daten.

Datentyp erstellen

Man kann die Daten sehr schön in Form eines Records hinzufügen. Dazu erstellen wir uns einen Record, der ungefähr so aussehen kann:

type
  PTreeData = ^TTreeData;
  TTreeData = record
    FCaption: String;
    FColumn1: String;
  end;

Zusätzlich zeigt der Pointer PTreeData jetzt auf den Record. Wieso wir jetzt an dieser Stelle einen Record benutzen, wird im weiter unten klarer. Du kannst dem Record beliebige Variablen hinzufügen.

Die Daten hinzufügen

Die nächsten Zeilen dienen hauptsächlich der Verständnis und tauchen in dieser Form nicht unbedingt im Quelltext auf.

Es wird wie gewohnt ein Node hinzugefügt. Die Adresse des Nodes wird in einer lokalen Variable festgehalten:

var
  Node: PVirtualNode;
begin
  Node:=VST.AddChild(nil);
end;

Dies sollte aus dem vorherigen Kapitel schon bekannt sein. Im nächsten Schritt holt man sich die Position des Objekts (das bisherige Objekt steht bisher auf nil). Dies geschieht folgendermaßen:

Data := VST.GetNodeData(Node);

Data muss in diesem Falle vom Typ PTreeData sein. PTreeData zeigt wiederum auf den Record TTreeData (also Data: PTreeData;). Nun füllen wir den Record mit Werten:

Data^.FCaption := 'Hallo';
  Data^.FColumn1 := 'Weiterer Wert';

Der Record ist jetzt mit Daten gefüllt. Diese Daten ‚gehören‘ jetzt zu dem Node. Jetzt gibt es aber noch einige Fallstricke, die zu beachten sind. Die Größe der Struktur muss dem Tree bekannt sein. Die macht man durch die Zuweisung:

VST.NodeDataSize := SizeOf(TTreeData);

Diese Zuweisung muss in der Regel nur einmal gesetzt werden. Verwendet man allerdings anders aufgebaut Daten muss der Werte aktualisiert werden. Alternativ kann man auch das Ereignis OnGetNodeDataSize benutzen, welches immer ausgelöst wird, wenn die Größe der Daten abgefragt wird.

Die komplette Procedure zum Hinzufügen eines Nodes mit Daten sieht also in etwa so aus. Das eigentliche Hinzufügen des Nodes habe ich in eine Funktion gesteckt:

function AddVSTStructure(AVST: TCustomVirtualStringTree; ANode: PVirtualNode;
 ARecord: TTreeData): PVirtualNode;
var
  Data: PTreeData;
begin
  Result:=AVST.AddChild(ANode);
  Data:=AVST.GetNodeData(Result);
  Avst.ValidateNode(Result, False);
  Data^.FCaption:=ARecord.FCaption;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
  I: Integer;
  TreeData: TTreeData;
begin
  VST.NodeDataSize:=SizeOf(TTreeData);
  VST.BeginUpdate;
  for I:=0 to 100 do
  begin
    TreeData.FCaption:='Node-Nummer: '+IntToStr(I);
    AddVSTStructure(VST,nil,TreeData);
  end;
  VST.EndUpdate;
end;

In diesem Beispiel werden dem Baum 100 Nodes+Daten hinzugefügt.

Die Funktion AddVSTStructure erwartet 3 Parameter. Einmal den Tree, welcher um ein Node bereichert werden soll. Dann als zweiten Parameter den übergeordneten Knoten (soll ein Root-Knoten hinzugefügt werden, muss dieser Parameter auf nil stehen) und als dritten Parameter den Record. Als Result gibt die Funktion – genauso wie AddChild – einen Zeiger auf den hinzugefügten Node zurück.

Die Methode ValidateNode initialisiert die Nodes. Dies ist später bei der Freigabe der Daten wichtig, da diese sonst im Speicher zurückbleiben würden. Dem ersten Parameter wird der zu initialisierende Node übergeben, der zweite Parameter gibt an, ob auch dessen Children initialisiert werden sollen. Dies ist in unserem Falle aber nicht nötig.

Daten auslesen

Schön. Jetzt haben wir Daten hinzugefügt, aber wir wissen noch nicht, wie man die Informationen wieder auslesen kann. Es folgt ein Beispiel.

procedure TForm1.VSTClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PTreeData;
begin
  Node := VST.FocusedNode;
  if not Assigned(Node) then
    Exit;

Data := VST.GetNodeData(Node);
Showmessage(Data.FCaption);
end;

Einen Teil dieser Procedure wirst du von dem letzten Kapitel her wiedererkennen. Es wird der selektierte Node im OnClick-Ereignis des Trees ermittelt.

Neu sind die letzten beiden Zeilen. Die Variable Data ist wieder ein Zeiger auf den Record TTreeData in Form von PTreeData. Mit der Funktion GetNodeData wird dieser Variable die Position des Records von dem ausgewählten Node übergeben. Per Showmessage wird dann der Wert, welcher in FCaption steht ausgegeben.

Ein bisschen Theorie

Fügt man ein Node hinzu, sieht es im Speicher ungefähr so aus:

------------------------------------------------
| interne Daten        |  user Daten           |
------------------------------------------------

Zuerst werden die einzelnen internen Node-Informationen abgelegt, danach folgen die User-Daten. Da die user-Daten dynamisch sind, muss die Größe der Daten vorher angegeben werden. Dies geschieht, wie schon gesagt, mit der Eigenschaft NodeDataSize. Die Funktion GetNodeData berechnet quasi den Startwert der User-Daten.

Freigabe der Daten

Oben habe ich das Thema Freigabe angesprochen. Die Daten belegen einen gewissen Platz im Speicher, der nach der Beendigung wieder freigegeben werden muss. Dies geschieht nicht automatisch, sondern muss manuell geschehen. Das Ereignis OnFreeNode ist dabei die richtige Anlaufstelle:

procedure TForm1.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Data: PTreeData;
begin
  Data := VST.GetNodeData(Node);
  if Assigned(Data) then
    Data.FCaption:='';
end;

Per GetNodeData holen wir uns die Speicheradresse der Daten. Bei Strings reicht es auch, die Variable auf einen Leerstring zu setzen.