Daten in TreeView

Rund um die LCL und andere Komponenten
catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Daten in TreeView

Beitrag von catweasel »

Moin

Ich spiele gerade mit dem Beispiel-Code für TreeView von Lazarus herum.

Um einfache Einträge hinzuzufügen geht das Programm wie folgt vor:

Code: Alles auswählen

[...]
   else begin
         {Get a name for the new node}
      sText := 'New node';
      InputQuery(  'New Node',  'Caption ?', sText  );
 
         {Add the node as a child of the selected node}
      with TreeView1.Items.AddChild(  TreeView1.Selected,  sText  ); do
      begin
         MakeVisible;
      end;
   end;
[...]
Ich frage mich wie man zu jedem Node noch Informationen als Tag oder ähnliches hinzufügen kann die nicht sichtbar sind.
Beispiel: Als "New Node" gebe ich einen Servernamen an, dann möchte ich irgendwo im Treeview die IP hinterlegen.
Irgendwie finde ich nicht wie das geht.

Kann mir jemand auf die Sprünge helfen?

Schönen Sonntag
Michael

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Daten in TreeView

Beitrag von Socke »

Code: Alles auswählen

[...]
   else begin
         {Get a name for the new node}
      sText := 'New node';
      InputQuery(  'New Node',  'Caption ?', sText  );
 
         {Add the node as a child of the selected node}
      with TreeView1.Items.AddChild(  TreeView1.Selected,  sText  ); do
      begin
         Data := nil; // hier kann man einen Zeiger auf beliebige Daten (auch Objekte) angeben. Nicht vergessen, diese auch wieder freizugeben!
         MakeVisible;
      end;
   end;
[...]
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Re: Daten in TreeView

Beitrag von catweasel »

Socke hat geschrieben:

Code: Alles auswählen

[...]
      with TreeView1.Items.AddChild(  TreeView1.Selected,  sText  ); do
      begin
         Data := nil; // hier kann man einen Zeiger auf beliebige Daten (auch Objekte) angeben. Nicht vergessen, diese auch wieder freizugeben!
         MakeVisible;
      end;
[...]
Puh - Mit Pointern habe ich immer so meine liebe Not. :oops:
Trotzdem Danke für den Hinweis.

Schönen Sonntag noch
Michael

catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Re: Daten in TreeView

Beitrag von catweasel »

Wie befürchtet bekomme ich es nicht hin:

Ich habe einen kurzen Text gefunden wo jemand einen Text in DATA lädt, wenn ich das aber bei mir einbaue und den TreeView als Datei speichere, ist mein Texttext nicht drin:

Als erstes habe ich den Record definiert:

Code: Alles auswählen

type
  prNodeData = ^rNodeData;
  rNodeData = record
     sText : string;
  end;

und danach die Variable zugeordnet:

Code: Alles auswählen

[...]
  with TreeView1.Items.AddChild(  TreeView1.Selected,  sText  ) do
    begin
->   {Allocate memory for the record}
->    Data := New(  prNodeData  );
->    {Set the nodes date time}
->    prNodeData(Data)^.sText := 'DataText';[/b]
 
       Imageindex:=1;
       SelectedIndex:=1;
 
       MakeVisible;
    end;
[...]
Als letztes wird der TreeView in einer Datei gespeichert.

Code: Alles auswählen

// Speichern des TreeView
procedure TForm1.SaveTreeView;
var
  F: TFileStream;
begin
  F := TFileStream.Create('c:\Temp\TreeView.txt', fmCreate or fmShareCompat);
  try
    F.WriteComponent(TreeView1);
  finally
    F.Free;
  end;
end;

In der Datei "c:\Temp\TreeView.txt", die dann beim Beenden des Programms erstellt, wird finde alle neuen Nodes die hinzugefügt wurden werden angezeigt, einen Eintrag "DataText" sehe ich aber nicht.
Der sollte aber doch eigendlich für jeden neuen Node-Eintrag vorhanden sein, oder?

Was fehlt denn da noch?

Gruß
Michael

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Daten in TreeView

Beitrag von Socke »

catweasel hat geschrieben:In der Datei "c:\Temp\TreeView.txt", die dann beim Beenden des Programms erstellt, wird finde alle neuen Nodes die hinzugefügt wurden werden angezeigt, einen Eintrag "DataText" sehe ich aber nicht.
Der sollte aber doch eigendlich für jeden neuen Node-Eintrag vorhanden sein, oder?
Nein, die Eigenschaft Data kann nicht gestreamt (eine Komponente in Text umwandeln). Woher soll TTreeView auch wissen, was du als Data übergibst. Ein Pointer kann alles mögliche sein; es ist nur "Zufall", dass es in deiner Anwendung ausgerechnet ein Zeiger auf einen Record ist.

Für dich heißt das: diese Daten musst du selbst abspeichern.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

wp_xyz
Beiträge: 5319
Registriert: Fr 8. Apr 2011, 09:01

Re: Daten in TreeView

Beitrag von wp_xyz »

Verwende statt AddChild die Methode AddChildObject, dann kannst du als letzten Parameter den Pointer auf die Daten übergeben. Wichtig ist noch, dass du im Event Handler OnDeletion noch die vorher erzeugten Pointer freigibst, sonst bleiben die Node-Daten als Lecks im Speicher. - Mache ich immer so und funktioniert wunderbar.

Code: Alles auswählen

 
var
  p: prNodeData;
//...
  P := New(prNodeData);
  p^.DataText := 'DataText';
  with TreeView1.Items.AddChildObject(  TreeView1.Selected,  sText, p) do begin
       Imageindex:=1;
       SelectedIndex:=1;
       MakeVisible;
  end;
 
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
  if Node.Data <> nil then begin
    Dispose(prNodeData(Node.Data));
    Node.Data := nil;
  end;
end;
 

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: Daten in TreeView

Beitrag von Scotty »

Warum benutzt ihr nicht einfach eine Klasse?

Code: Alles auswählen

type 
  TMyNodeData=class
    Text:string
  end;
 
aNodeData:=TMyNodeData.Create;
aNodeData.Text:='Hello World';
TreeView1.Items.AddChildObject(aNode, aText,aNodeData);
 

catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Re: Daten in TreeView

Beitrag von catweasel »

Scotty hat geschrieben:Warum benutzt ihr nicht einfach eine Klasse?
[...]
Danke für die Hilfe. Werde ich gleich mal testen wenn ich zu Hause bin.

catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Re: Daten in TreeView

Beitrag von catweasel »

Scotty hat geschrieben:

Code: Alles auswählen

type 
  TMyNodeData=class
    Text:string
  end;
 
aNodeData:=TMyNodeData.Create;
aNodeData.Text:='Hello World';
TreeView1.Items.AddChildObject(aNode, aText,aNodeData);
 
Es ist korrekt das auch hier der Text "Hello World' auch hier nicht im TreeView gespeichert wird, sondern ich wieder separat speichern muß, richtig?

Benutzeravatar
theo
Beiträge: 11080
Registriert: Mo 11. Sep 2006, 19:01

Re: Daten in TreeView

Beitrag von theo »

catweasel hat geschrieben: Es ist korrekt das auch hier der Text "Hello World' auch hier nicht im TreeView gespeichert wird, sondern ich wieder separat speichern muß, richtig?
Ich würde mal sagen, da wird alles "im Treeview" gespeichert, aber vllt. verstehe ich deine Frage nicht.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Daten in TreeView

Beitrag von Socke »

catweasel hat geschrieben:Es ist korrekt das auch hier der Text "Hello World' auch hier nicht im TreeView gespeichert wird, sondern ich wieder separat speichern muß, richtig?
Ja, auch in diesem Fall weiß der TreeView nicht, wie er das Objekt abspeichern oder lesen soll.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

wp_xyz
Beiträge: 5319
Registriert: Fr 8. Apr 2011, 09:01

Re: Daten in TreeView

Beitrag von wp_xyz »

Leider ist das Speichern eines Trees in der LCL ziemlich gekapselt. Du musst dir deine eigene Speichern-Routine schreiben. Eine Vorlage findest du in treeview.inc (in (lazarus)\lcl\include), procedure TTreeStrings.SaveToStream. Du musst eigentlich nur in der Zeile NodeStr := NodeStr + ANode.Text + EndOfLine statt dem Text auch das String-Äquivalent deiner Daten einbauen, etwa so: (Beachte aber, dass diese Datei so nicht wieder korrekt eingelesen wird, du müsstest dann auch noch ein ReadTreeFromStream schreiben, aber das kannst du jetzt selbst, oder?)

Code: Alles auswählen

 
procedure SaveTreeToStream(ATree: TTreeView; Stream: TStream);
const
  TabChar = #9;
  EndOfLine = #13#10;
var
  i: Integer;
  ANode: TTreeNode;
  NodeStr: string;
 
  function DataAsString(ANode: TTreeNode): String;
  begin
    if ANode.Data <> nil then
      Result := prNodeData(ANode.Data)^.DataText
       // und natürlich auch die anderen Datenfelder anfügen
    else
      Result := '';
    end;
 
begin
  if ATree.Items.Count > 0 then begin
    ANode := ATree.Items[0];
    while ANode <> nil do
    begin
      NodeStr := '';
      for i := 0 to ANode.Level - 1 do NodeStr := NodeStr + TabChar;
      NodeStr := NodeStr + ANode.Text + ' [' + DataAsString(ANode) + ']' + EndOfLine;
      Stream.Write(Pointer(NodeStr)^, Length(NodeStr));
      ANode := ANode.GetNext;
    end;
  end;
end;  
 

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: Daten in TreeView

Beitrag von Scotty »

catweasel hat geschrieben:Puh - Mit Pointern habe ich immer so meine liebe Not. :oops:
Ich wollte mit "Klasse" nur darauf hinweisen, dass diese eigenartigen Pointer-Konstrukte ersetzt werden können.

Statt

Code: Alles auswählen

 
type 
  PNodeData=^TNodeData;
  TNodeData=record
    DataText:string;
  end;
 
  if ANode.Data <> nil then
    Result := prNodeData(ANode.Data)^.DataText
 
geht es auch so:

Code: Alles auswählen

 
type
  TMyNodeData=class
    DataText:string;
  end;
 
  if ANode.Data <> nil then
    Result := TMyNodeData(ANode.Data).DataText
 

catweasel
Beiträge: 230
Registriert: Di 17. Mär 2009, 10:51
OS, Lazarus, FPC: Win10 64Bit // Linux Mint 20.0 - (L 2.2.0 FPC 3.2.2)

Re: Daten in TreeView

Beitrag von catweasel »

wp_xyz hat geschrieben:[...]Beachte aber, dass diese Datei so nicht wieder korrekt eingelesen wird, du müsstest dann auch noch ein ReadTreeFromStream schreiben, aber das kannst du jetzt selbst, oder?
[...]
Ich habe mir den Quelltext von

Code: Alles auswählen

procedure TTreeStrings.LoadTreeFromStream(Stream: TStream);
angesehen, aber irgendwie gucke ich rauf wie ein Schw.. ins Uhrwerk. :cry:

wp_xyz
Beiträge: 5319
Registriert: Fr 8. Apr 2011, 09:01

Re: Daten in TreeView

Beitrag von wp_xyz »

Versuche mal zu verstehen, was in dieser Routine passiert: Du hast den Tree in einer Textdatei gespeichert, jeder Knoten eine Zeile, wobei je nach Level um einen Tabulator weiter eingerückt wird, und die dem Knoten zugordneten Daten sind, in eckige Klammern gesetzt, in den String eingebaut. In der von dir genannten Prozedur wird die Textdatei Zeile für Zeile eingelesen, und es werden Nodes erzeugt, wobei der Level jedes Nodes aus der Anzahl der Tabulatoren im Text ermittelt wird. AddChild sind Standardmethoden des TreeView (genauer: der TreeNodes), vielleicht hilft dir dazu auch die Erklärung im Tutorial http://wiki.lazarus.freepascal.org/TTreeView. GetBufStart holt sich aus der eingelesenen Zeile den für den Node gespeicherten Text und die Anzahl der Tabulatoren, also den Level-Wert dieses Nodes - das ist keine Standardmethode, aber mit dem Wissen, was sie macht, kannst du sie einfach nachprogrammieren. Schließlich musst du den per GetBufStart ermittelten Text noch zerlegen in den Node-Text und in die Daten, die, als String gewandelt, als Data dem Node zugeordnet sind. Probier's mal. Ist vielleicht nervig, wenn man das mal durchkaut, aber man lernt sehr viel dabei.

Antworten