Autor Beitrag
JanHH
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Fr 28.02.03 04:48 
Hallo Forum,

treeview und kein Ende.. Einen solchen zu Laden und zu Speichern ist ja relativ einfach (TTreeView.SaveToFile bzw. -.LoafFromFile), aber was ist mit den damit verbundenen Daten (TTreeNode.Data)? Auch diese (ist bei mir jedeweils ein record bzw. ein ^record) zu laden und zu speichern ist kein Problem, nur werden doch die TreeNodes sequentiell in der Reihenfolge ihres Entstehens im Items-Array abgelegt, und die Data-Pointer deshalb logischerweise beim sequentiellen Speichern auch in dieser Reihenfolge.. wenn der Tree nun aber wieder geladen wird, geht die ursprüngliche Reihenfolge verloren, und das Items-Array wird neu angelegt, dabei halt umsortiert, und wenn ich die damit verbundenen Daten-Objekte dann einlese, ist die zuordnung nicht mehr korrekt.. und ich bin da ziemlich ratlos wie man das "einfach" lösen kann. Die Delphi-Hilfe erzählt da irgendwas von BLOB-Streams, was ist das??

Weiss irgend jemand Rat?

Danke und Gruß,
Jan
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Fr 28.02.03 15:28 
Hi.

Ich sehe zwei Möglichkeiten:

1. die property 'ItemID' des nodes in deinem record speicher und nachher wieder zuordnen. Musst aber testen ob sie auch gleich bleibt.

2. Main favorit: Eine klasse von TTreeNode ableiten und ein zusätzliches published property definieren. zB. 'RecordIndex'. Vor dem speichern allen nodes das record index geben. Nach dem laden alle nodes durchgehen und das richtige record linken!


mfg maximus.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Fr 28.02.03 15:50 
2. klingt gut, danke!

Gruß
Jan
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Fr 28.02.03 23:37 
Hmm.. funktioniert doch nicht, glaube ich, ohne es ausprobiert zu haben. DENN: Wenn ich die treeview mittels SaveToFile/-Stream speichere, wird er ja nur als text gespeichert.. und die ID wird nicht mitgespeichert, also vermutlich auch durchaus geändert manchmal, und wenn ich zum Baum-Zusammenbauen ursprünglic nicht TTreeNode, sondern was davon abgeleitetes benutzt haben, dann wird das ja beim lesen nicht wieder so gemacht, sondern es werden nur die normalen TreeNode-Objekte genommen, und die Bezüge sind wieder alle weg.. Ich müsste also eher gleich die ganze TTreeView-Klasse ableiten und sowohl die TreeNodes durch eigene ersetzten, als auch die LoadFromFile-Methode durch ne eigenen ersetzen. oder? *ächz*

Die einfachste, wenn auch unelegante, Methode, das Problem zu lösen, ist meines erachtens nach, den Bezug zwischen Data-Record und TreeNode über die TreeNode-Caption herzustellen, welche in meinem Anwendungsfall eindeutig identifizierend ist.

Hat jemand spontan Inspriation zu meinen Ausführungen? Oder hab ich irgendwas übersehen oder falsch verstanden?

Danke und Gruß,
Jan
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: Sa 01.03.03 15:18 
Hallo JanHH!

Es hat ne Weile gedauert, aber ich glaube es klappt jetzt:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
type
  TNodeType = (ntNew, ntChild, ntNormal);

procedure SaveTree(const FileName: Stringconst Nodes: TTreeNodes);
  procedure WriteString(const FS: TFileStream; const S: String);
  var
    L: Word;
  begin
    L := Length(S);
    FS.Write(L, SizeOf(L));
    FS.Write(S[1], L);
  end;

var
  I: Integer;
  Node, Parent: TTreeNode;
  FS: TFileStream;
  NodeType: TNodeType;
  Rec: PRecord;
begin
  FS := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
  with FS do begin
    try
      Parent := nil;
      I := Nodes.Count;
      Write(I, SizeOf(I));
      for I := 0 to Nodes.Count - 1 do begin
        Node := Nodes[I];
        if Node.Parent = nil then
          NodeType := ntNew
        else if Node.Parent <> Parent then
          NodeType := ntChild
        else
          NodeType := ntNormal;
        WriteString(FS, Node.Text);
        Rec := PRecord(Node.Data);
        Write(Rec, SizeOf(PRecord));
        Write(NodeType, SizeOf(NodeType));
        Parent := Node.Parent;
      end;
    finally
      Free;
    end;
  end;
end;

procedure LoadTree(const FileName: Stringconst Nodes: TTreeNodes);
  function ReadString(const FS: TFileStream): String;
  var
    L: Word;
    S: String;
  begin
    S := '';
    FS.Read(L, SizeOf(L));
    SetLength(S, L);
    FS.Read(PChar(S)^, L);
    Result := S;
  end;

var
  I: Integer;
  FS: TFileStream;
  Rec: PRecord;
  S: String;
  NodeType: TNodeType;
  Node: TTreeNode;
begin
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  with FS do begin
    try
      Node := nil;
      Read(I, SizeOf(I));
      for I := (I - 1downto 0 do begin
        S := ReadString(FS);
        Read(Rec, SizeOf(PRecord));
        Read(NodeType, SizeOf(NodeType));
        case NodeType of
          ntNew:
            Node := Nodes.AddObject(nil, S, Rec);
          ntChild:
            Node := Nodes.AddChildObject(Node, S, Rec);
          ntNormal:
            Node := Nodes.AddObject(Node, S, Rec);
        end;
      end;
    finally
      Free;
    end;
  end;
end;
Den Typ PRecord musst du halt auf deinen Record anpassen. Ich muss gestehen, dass er bei mir noch die Daten falsch läd.
Ich konnte den Fehler bis jetzt nocht nicht finden, vielleicht findest du ihn.
Probier es einfach mal bei dir aus, vielleicht klappt es ja bei dir!

Gruß Hape!

Moderiert von user profile iconKlabautermann: Code durch Delphi-Tags ersetzt.

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Sa 01.03.03 20:05 
Hallo,

vielen Dank für die Mühe, aber funktioniert das wirklich!? Kann mir gar nicht vorstellen, das der Baum auf diese Weise korrekt gespeichert wird. Du speicherst ja nur die Information, OB ein Node Child- oder Parentnode ist, nicht, von WEM, wenn ich das richtig sehe.. also, die Bezüge der nodes aufeinander gehen verloren!? Würde ich zumindest vermuten.. Dein Ansatz ist ja, den Baum (bzw. die einzelnen Knoten) abzuklappern und quasi Binär zu speichern.. Hmm, sollte ich vielleicht auch mal ausprobieren. Danke also für die Mühe und Inspiration! Zumindest das zuordnen des Data-Records über die Caption ist als "Notlösung" ja auf jeden Fall möglich.. gar nicht so tirival, so ein TreeView, sehe ich das richtig?

Grüße
Jan
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: Sa 01.03.03 20:15 
Hallo JanHH!

So funktioniert es tatsächlich. Das (oder der?) Node muss gar nicht wissen wer das Parent ist, denn dass ergibt sich zwangsweise aus der Reihenfolge!
Deshalb probier es erstmal aus, bevor du urteilst, denn es funktioniert ;)!
Das einzige, was beim mir nicht geklappt hat, war das Laden der Records. Das dürfte aber für dich kein großes Problem sein das zu beheben. Die Reihenfolge hat immer gestimmt und wird auch immer stimmen!

Gruß wulfskin!

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Sa 01.03.03 20:47 
Hallo,

meine Vermutung ist halt, das die Reihenfolge zwar anfangs "OK" ist, aber wenn man Knoten hin- und herverschiebt (property Owner) sich die Parent-Child-Beziehungen verändern, aber ja nicht der Listenplatz, den ein Node im Items-Array hat, und alles durcheinandergerät.. Oder?

Gruß
Jan
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: Sa 01.03.03 20:55 
JanHH hat folgendes geschrieben:
Hallo,

meine Vermutung ist halt, das die Reihenfolge zwar anfangs "OK" ist, aber wenn man Knoten hin- und herverschiebt (property Owner) sich die Parent-Child-Beziehungen verändern, aber ja nicht der Listenplatz, den ein Node im Items-Array hat, und alles durcheinandergerät.. Oder?

Gruß
Jan
Sorry, blick ich net! Der Aufbau wird so geladen, wie er davor war. Versuch es doch einfach mal, dann kannst du ja immer noch meckern!

Gruß wulfskin!

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Sa 01.03.03 21:05 
Naja die Reihenfolge der Knoten im Items-Array enstpricht nicht unbedingt der, wie sie in der Baumdarstellung sind (also von oben nach unten, so ganz visuell *g*), da man sie ja mit drag&drop hin-und-herschieben kann (in meiner Applikation). Und dabei ändert sich ja soweit ich weiss nicht die Reihenfolge im Items-Array, sonder nur die Owner-Property. Daher bezweifle ich das das so geht. Bei einem Baum, der nicht "editierbar" ist, sicher, aber wenn man darin was verschoben hat.. und ich meckere auch gar nicht, sondern denke lediglich drüber nach, mittlerweile reichlich frustriert ;).

Gruß und Danke,
Jan
wulfskin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1349
Erhaltene Danke: 1

Win XP
D5 Pers (SSL), D2005 Pro, C, C#
BeitragVerfasst: Sa 01.03.03 21:19 
JanHH hat folgendes geschrieben:
Naja die Reihenfolge der Knoten im Items-Array enstpricht nicht unbedingt der, wie sie in der Baumdarstellung sind (also von oben nach unten, so ganz visuell *g*), da man sie ja mit drag&drop hin-und-herschieben kann (in meiner Applikation). Und dabei ändert sich ja soweit ich weiss nicht die Reihenfolge im Items-Array, sonder nur die Owner-Property. Daher bezweifle ich das das so geht. Bei einem Baum, der nicht "editierbar" ist, sicher, aber wenn man darin was verschoben hat.. und ich meckere auch gar nicht, sondern denke lediglich drüber nach, mittlerweile reichlich frustriert ;).

Gruß und Danke,
Jan
Ahhh, jetzt versteh ich!

Wenn das so ist, wie du sagst (habe es noch getestet), dann geht es natürlich nicht so, wie ich das gemacht habe.
Dann müsste man den Baum durchgehen. Mit GetFirstNode hat man ja ein Anfang und man kann sich durch die Childs durchhangeln. Das einzige Problem das ich dann noch sehe ist das nächste "oberste" Item zu bekommen! Wenn du weisst, wie man an das kommt, dürfte das ganze kein Problem sein!

Gruß wulfskin!

_________________
Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Sa 01.03.03 21:35 
Tja ist wohl so.. ich werd das mal machen und den code dann posten, können sicher viele leute gebrauchen ;) Den Baum rekursiv durchzugehen ist ja prinzipiell kein problem, und in die datei müssen dann halt push- und pop-markierungen geschrieben werden.. nervig, aber möglich.

Naja und die andere Möglichkeit ist halt die Verknüpfung über die Caption des Nodes.. doof aber funzt sofern diese eindeutig ist.

Ich werds mal testen, melde mich dann wieder..

Gruß
Jan
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: So 02.03.03 04:31 
es funktioniert :-).. habe ein neues thema draus gemacht.

Moderiert von user profile iconTino: Beitrag aus dem neuen Topic hier eingefügt.

Hallo,

der folgende Code speichert und lädt einen TTreeView INKLUSIVE der Data-Records, die mit den Nodes verknüpft sind.. vielleicht interessiert das jemanden ;).

WriteInt, WriteString, ReadInt und ReadString sind Hilfsfunktionen zum Laden und Speichern selbiger Daten, habe die wegen der Trivialität weggelassen, und WriteNodeData bzw. ReadNodeData speichern und laden den Data-Record (bzw. pRecord).

Sorry für die Formatierung, wie fügt man sourcecode hier "richtig" ein? Bin irgendwie planlos was das angeht..

Grüße
Jan
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
procedure TForm1.WriteTreeView(f: TFileStream);
begin
  WriteInt(f, 0); // eine Null Vorweg als push-pop-Markierung für das oberste Element
  WriteTreeNode(TreeView1.Items[0], f);
  WriteInt(f, 99); // Ende-Marker
end;

procedure TForm1.WriteTreeNode(node: TTreeNode; f: TFileStream);
var
  myNode: TTreeNode;
begin
  // Format pro Knoten im FileStream:
  //
  // abwechselnd string (node-caption) und int:
  // push-pop-markierung
  //     0=normal
  //     1=push (d.h., jetzt kommt ein child-node)
  //     2=pop (d.h., keine siblings mehr vorhanden,
  //            wieder eine Ebene höher weitermachen,
  //            hier folgt dann allerdings kein String)

  // 1. node selber
  WriteString(f, node.Text);
  WriteNodeData(f, node.Data);

  // 2. erstes kind
  myNode := node.getFirstChild;
  if assigned(myNode) then
  begin
    // push
    WriteInt(f, 1);
    WriteTreeNode(myNode, f);
  end;

  // 3. nachfolger
  myNode := node.GetNextSibling;
  if assigned(myNode) then
  begin
    // kein push, kein pop
    WriteInt(f, 0);
    WriteTreeNode(myNode, f);
  end
  else
  begin
    // kein sibling mehr, also pop
    WriteInt(f, 2);
  end;
end;

procedure TForm1.LoadTreeView(f: TFileStream; tree: TTreeView);
var
  node: TTreeNode;
begin
  node := nil;
  tree.Items.Clear;
  LoadTreeNode(f, tree, node);
end;

procedure TForm1.LoadTreeNode(f: TFileStream; tree: TTreeView; node: TTreeNode);
var
  s: String;
  nodeType: Integer;
  myNode, myParentNode: TTreeNode;
begin
  myParentNode := node;
  nodeType := -1;
  while not(nodeType=99do
  begin
    case nodeType of
      0:
      begin
        ReadString(f, s);
        myNode := tree.Items.AddChild(myParentNode, s);
        myNode.Data := ReadNodeData(f);
      end;
      1:
      begin
        ReadString(f, s);
        myParentNode := myNode;
        myNode := tree.Items.AddChild(myParentNode, s);
        myNode.Data := ReadNodeData(f);
      end;
      2:
      begin
      if assigned(myParentNode) then
        myParentNode := myParentNode.Parent;
      end;
    end;
    ReadInt(f, nodeType);
  end;
end;


Moderiert von user profile iconTino: Code-Tags hinzugefügt.
Moderiert von user profile iconKlabautermann: Code durch Delphi-Tags ersetzt.
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Mo 03.03.03 17:03 
Hmm, das laden funktioniert doch noch nicht, die Data-Records und die Knoten werden nicht richtig zugeordnet.. seltsam *frust*.

Gibts nicht doch irgendwo sowas wie DIE trivial-Lösung dafür?

Jan
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Mo 03.03.03 17:24 
Es geht doch, der Bug war woanders in meinem Programm, der obige Code ist also RICHTIG.. Sorry. und sorry für mein konfuses geposte..

Jan
Dr. Phil
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 66

Win XP
Delphi 7 Prof.
BeitragVerfasst: Do 26.08.04 00:11 
Hallo!

Sorry, dass ich so ein altes Thema wieder hier rauf hole, aber von Streams hab ich herzlich wenig Ahnung.

Ich würde gern wissen wie die Hilfsfunktionen WriteInt, WriteString, ReadInt und ReadString ausschauen könnten, ich finde die garnicht so trivial ;)

Danke im Voraus!

_________________
self-improvement is masturbation;
self-destruction is the answer - Tyler Durden


Zuletzt bearbeitet von Dr. Phil am Do 26.08.04 14:33, insgesamt 1-mal bearbeitet
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Do 26.08.04 02:34 
So hab ich das gelöst.

Gruß
Jan

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
unit MyFiles;

interface

uses Classes, SysUtils;

procedure WriteInt(var f: TFileStream; i: Integer);
procedure ReadInt(f: TFileStream; var i: Integer);

procedure WriteReal(var f: TFileStream; r: real);
procedure ReadReal(f: TFileStream; var r: real);

procedure WriteString(var f: TFileStream; s: String);
procedure ReadString(f: TFileStream; var s: String);

procedure WriteBoolean(var f: TFileStream; b: Boolean);
procedure ReadBoolean(f: TFileStream; var b: Boolean);

implementation

procedure WriteInt(var f: TFileStream; i: Integer);
begin
  f.WriteBuffer(i, SizeOf(Integer));
end;

procedure WriteReal(var f: TFileStream; r: real);
begin
  f.WriteBuffer(r, SizeOf(real));
end;

procedure WriteString(var f: TFileStream; s: String);
var
  l: Integer;
begin
  l := Length(s);
  f.WriteBuffer(l,SizeOf(Integer));
  f.WriteBuffer(PChar(s)^,l);
end;

procedure WriteBoolean(var f: TFileStream; b: Boolean);
begin
  f.WriteBuffer(b, SizeOf(Boolean));
end;

procedure ReadInt(f: TFileStream; var i: Integer);
begin
  f.ReadBuffer(i, SizeOf(Integer));
end;

procedure ReadReal(f: TFileStream; var r: real);
begin
  f.ReadBuffer(r, SizeOf(real));
end;

procedure ReadString(f: TFileStream; var s: String);
var
  p: PChar;
  l: Integer;
begin
  f.ReadBuffer(l,SizeOf(Integer));
  p := AllocMem(l*2);
  f.ReadBuffer(p^,l);
  s := String(p);
  FreeMem(p);
end;

procedure ReadBoolean(f: TFileStream; var b: Boolean);
begin
  f.ReadBuffer(b, SizeOf(Boolean));
end;

end.


Moderiert von user profile iconKlabautermann: Code durch Delphi-Tags ersetzt.
Dr. Phil
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 66

Win XP
Delphi 7 Prof.
BeitragVerfasst: Do 26.08.04 10:19 
Danke!
Und was ist mit WriteNodeData und ReadNodeData?

Ich möchte das Beispiel komplett übernehmen, also wär das angenehm wenn du mir zeigen könntest wie die prozeduren bei dir aussehen.

Ach und super, dass sich jemand die Arbeit dafür gemacht hat!

_________________
self-improvement is masturbation;
self-destruction is the answer - Tyler Durden
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Do 26.08.04 10:59 
JanHH hat folgendes geschrieben:
So hab ich das gelöst.
...


Das wäre nicht unbedingt nötig gewesen. Genau die selben funktionen bieten die stream-hifsklassen TReader und TWriter. Und noch vieles mehr.

Ich sag das nur damit damit andere sich das etvl. zu nutze machen können, nicht um diene unit zu kritisieren.

_________________
mfg.
mâximôv
JanHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1



BeitragVerfasst: Do 26.08.04 15:40 
Ich glaub es gibt ne ganze Menge Hilfsfunktionen in Delphi, von denen man nicht unbedingt was weiss und die man redundanterweise dann selber nachprogrammiert.

Ich kann mich an den ganzen TreeView-Kram gar nicht mehr so genau erinnern und hab das mittlerweile eh verworfen (da ein treeview-speichern unnötig ist in einem vernünftig entworfenen Programm, da das speichern von daten direkt im treeview designmässig ziemlicher Müll ist, allerdings mag es bei eher kleinen Programmen ok sein), aber das Lesen und Schreiben der NodeData-Objekte hängt natürlich vom Objekt an sich ab, insofern kann man das kaum generell beantworten. Am besten, man hat einen Typ TNodeData, ein NodeData ist halt ein myNodeData: TNodeData, und die Klasse hat eine Funktion Read und Write.

Gruß
Jan