| 
			Author: Tomas Rutkauskas
I'd like to use the TreeView component for hierarchizing some data. For this, I 
need to add to every node an integer property which will refer to the primary key 
field of an associated database. Alas, I fear that the TreeView "SaveToFile" and 
"LoadFromFile" methods save/ load only the Text property! Then, how can I save and 
load this integer property (and by the way, the imageindex) for every node?
Answer:
By writing your own save and load routines. Untested! Don't forget to rewind the 
stream before loading when you test this code.
1   
2   procedure SaveTreeviewToStream(tv: TTreeview; S: TStream);
3   var
4     writer: TWriter;
5     node: TTreeNode;
6   begin
7     Assert(Assigned(tv));
8     Assert(Assigned(S));
9     writer := TWriter.Create(S, 4096);
10    try
11      node := tv.Items[0];
12      writer.WriteListBegin;
13      while node <> nil do
14      begin
15        writer.WriteInteger(node.level);
16        writer.WriteString(node.Text);
17        writer.WriteInteger(node.Imageindex);
18        writer.WriteInteger(Integer(node.data));
19        node := node.GetNext;
20      end;
21      writer.WriteListEnd;
22      writer.FlushBuffer;
23    finally
24      writer.Free;
25    end;
26  end;
27  
28  procedure LoadTreeviewFromStream(tv: TTreeview; S: TStream);
29  var
30    reader: TReader;
31    node: TTreeNode;
32    level: Integer;
33  begin
34    Assert(Assigned(tv));
35    Assert(Assigned(S));
36    tv.Items.BeginUpdate;
37    try
38      tv.Items.Clear;
39      reader := TReader.Create(S, 4096);
40      try
41        node := nil;
42        reader.ReadListBegin;
43        while not Reader.EndOfList do
44        begin
45          level := reader.ReadInteger;
46          if node = nil then
47            {create root node, ignore its level}
48            node := tv.Items.Add(nil, '')
49          else
50          begin
51            if level = node.level then
52              node := tv.Items.Add(node, '')
53            else if level > node.level then
54              node := tv.Items.AddChild(node, '')
55            else
56            begin
57              while Assigned(node) and (level < node.level) do
58                node := node.Parent;
59              node := tv.Items.Add(node, '');
60            end;
61          end;
62          node.Text := Reader.ReadString;
63          node.ImageIndex := Reader.ReadInteger;
64          node.Data := Pointer(Reader.ReadInteger);
65        end;
66        reader.ReadListEnd;
67      finally
68        reader.Free;
69      end;
70    finally
71      tv.items.Endupdate;
72    end;
73  end;
 
I'd rather suggest to use the data pointer as a pointer to a real object, not as integer (in the SaveTreeviewToStream procedure). You could add more complex info inside this object, like type information, or even the data objects itself. Type information is essential if your treeview browses through different tables of your database.
			 |