From the presentation given to the Australian Delphi User Group on 19th April 1999
by Andy Bulka abulka@netspace.net.au

The following bulleted points have been converted from the powerpoint presentation. Quite a bit of verbal explanation is, of course, missing.
3 techniques, all involve overriding:
Plus we need to define our own treeview so we can override a few choice methods

So why not:

We are going to build the application, pictured above. Clicking on each tree node will display data in the edit fields (see blue line). Full source code below. For the unit code + form dfm + executable download this.
unit andyStreamTree;
{
From the presentation given to AGUG on 19th April 1999
by Andy Bulka abulka@netspace.net.au
This single unit / form illustrates the principles of
persistence through component streaming, by showing you
how to save a treeview to disk.
}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, comctrls;
type
TForm4 = class(TForm)
Button1CREATETREE: TButton;
Button1FREETREE: TButton;
Button1POPULATE: TButton;
Button1STREAMOUT: TButton;
Button2STREAMIN: TButton;
Edit1: TEdit;
Edit2: TEdit;
Button1SAVERECORD: TButton;
procedure Button1CREATETREEClick(Sender: TObject);
procedure Button1FREETREEClick(Sender: TObject);
procedure Button1POPULATEClick(Sender: TObject);
procedure Button1STREAMOUTClick(Sender: TObject);
procedure Button2STREAMINClick(Sender: TObject);
procedure Button1SAVERECORDClick(Sender: TObject);
private
procedure clickFest(sender: TObject);
procedure canDrop(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure draggy(Sender, Source: TObject; X, Y: Integer);
{ Private declarations }
public
{ Public declarations }
end;
Ttree = class(TTreeview)
private
Ftest1 : string;
procedure clear;
protected
procedure getchildren(proc: TGetChildProc; root: Tcomponent); override;
procedure loaded; override;
published
property test1: string read Ftest1 write Ftest1;
end;
Tinfo = class(Tcomponent)
private
Fs1 : string;
Fs2 : string;
published
property address: string read Fs1 write Fs1;
property phone: string read Fs2 write Fs2;
end;
var
Form4: TForm4;
tree: Ttree;
implementation
{$R *.DFM}
procedure TForm4.Button1CREATETREEClick(Sender: TObject);
begin
tree := Ttree.create(self);
tree.parent := self;
tree.height := tree.height * 3;
tree.width := tree.width * 2;
tree.OnClick := clickFest;
tree.DragMode := dmAutomatic;
tree.OnDragDrop := draggy;
tree.OnDragOver := canDrop;
end;
procedure TForm4.Button1FREETREEClick(Sender: TObject);
begin
tree.free;
tree := nil;
end;
procedure TForm4.Button1POPULATEClick(Sender: TObject);
var
obj: Tinfo;
begin
obj := Tinfo.create(tree);
obj.address := '123 street';
obj.phone := '999335533';
tree.items.AddChildObject(nil, 'hello',obj);
obj := Tinfo.create(tree);
tree.items.AddChildObject(nil, 'world',obj);
tree.test1 := 'laughing is not clowing';
end;
procedure TForm4.Button1STREAMOUTClick(Sender: TObject);
begin
WriteComponentResFile('c:\windows\desktop\andyout.dfm', tree);
end;
procedure TForm4.Button2STREAMINClick(Sender: TObject);
begin
tree.clear;
RegisterClasses([Ttree,Tinfo]);
ReadComponentResFile('c:\windows\desktop\andyout.dfm', tree);
end;
procedure TForm4.clickFest(sender: TObject);
begin
if (tree.selected <> nil) and (tree.selected.data <> nil) then
begin
edit1.text := Tinfo(tree.selected.data).address;
edit2.text := Tinfo(tree.selected.data).phone;
end;
end;
procedure Ttree.getchildren(proc: TGetChildProc; root: Tcomponent);
var
i: integer;
begin
for i := 0 to items.count-1 do
Tinfo(items[i].data).name := '';
for i := 0 to items.count-1 do
begin
Tinfo(items[i].data).name := 'ID'+inttostr(i);
proc( items[i].data );
end
end;
procedure Ttree.loaded;
var
i: integer;
begin
for i := 0 to items.count-1 do
items[i].data := findcomponent('ID'+inttostr(i));
end;
procedure Ttree.clear;
var
i: integer;
begin
for i := ComponentCount - 1 downto 0 do
if components[i].ClassName = 'Tinfo' then
RemoveComponent(components[i]);
for i := items.count-1 downto 0 do
items[i].Delete;
end;
procedure TForm4.Button1SAVERECORDClick(Sender: TObject);
var
info : Tinfo;
begin
if tree.selected is TTreeNode then begin
info := tree.selected.data;
info.address := edit1.text;
info.phone := edit2.text;
end
else beep;
end;
procedure TForm4.canDrop;
begin
Accept := True;
end;
procedure TForm4.draggy;
var
TargetNode, SourceNode: TTreeNode;
begin
TargetNode := tree.GetNodeAt (X, Y);
if TargetNode <> nil then
begin
SourceNode := tree.Selected;
SourceNode.MoveTo (TargetNode, naAddChildFirst);
tree.Selected := TargetNode;
end;
end;
end.