首页  编辑  

TreeView上的节点连同其关联的对象的保存

Tags: /超级猛料/VCL/TreeView/   Date Created:
保存对象要稍难一些,因为在TreeNode中只存了个指针,除非TreeNode.Data是一个能用流操作的对象。如果是这样:(简单示范)
var
 s1: TFileStream;
 s2: TMemoryStream;
 nCount, i: Inteter;
 
 procedure CopyStream( sSrc, sDest: TStream );
 begin
   nCount := sSrc.Size;
   sDest.Write( nCount, sizeof(nCount) ); // 请写入字节数
   sDest.CopyFrom( sSrc, 0 ); // 写入TreeView的内容,第二个参数为0表示全部复制
   sSrc.Size := 0;  // 清掉以前数据
 end;
 
begin
 s2 := TMemoryStream.Create;
 // 保存到文件
 s1 := TFileStream.Create( '文件名', fmCreate );
 TreeView.SaveToStream( s2 );
 CopyStream( s2, s1 );
 // 下面写入TreeNode的Data
 for i:=0 to TreeView.Items.Count-1 do
 begin
   if Assigned(TreeView.Items[i].Data) then
   begin
     s2.Write( i, sizeof(i) );  // 保存序号,如果你有更好标识方法,可以代替
     TYourDataClass(TreeView.Items[i].Data).SaveToStream( s2 ); // TYourDataClass只是假定的名字
     CopyStream( s2, s1 );
   end;
 end;
 
 s1.Free; // 在Free之前它会保存的
 
 // 从文件读取
 s1 := TFileStream.Create( '文件名', fmOpenRead );
 s1.ReadBuffer( nCount, sizeof(nCount) );
 s2.CopyFrom( s1, nCount );
 TreeView.LoadFromStream( s2 );
 // 下面读入TreeNode的Data
 while s1.Position<s1.Size do
 begin
   s1.ReadBuffer( i, sizeof(i) );
   s1.ReadBuffer( nCount, sizeof(nCount) );
   s2.CopyFrom( s1, nCount );
   TreeView.Items[i].Data := TYourDataClass.Create; // 当然,可能Create调用格式是另外的
   TYourDataClass(TreeView.Items[i].Data).LoadFromStream( s2 );
 end;
 s1.Free;
 
 s2.Free;
 
这个例子不一定能满足你的要求,不过至少你可以参考一下。因为在你的程序里,可能TreeView.Items[i].Data还有别的变量指着。但你可以变化一下。比如倒着赋值。
******************
我曾经这样来记录我的TREEVIEW,不知道和你的想法是否一致:
{伪代码}
{假设表中有一个TREEVIEW,这里定义一个结构做为节点关联的DATA}
type PitemData=^TItemData;
    TItemData=record
    caption:string;
    data:integer;
end;
----------------------------------------
建树的过程:
循环:
 新建一个PITEMDATA的指针,
 为指针的域赋值,
 新建一个节点,
 节点的DATA=新指针,
保存文件的过程:
创建一个新文件:
得到当前树节点的最顶层节点数,向文件中写节点数,开始循环节点数,遍历每个节点
然后向文件中分别写入是否有子节点,有多少个子节点,每个节点下指针的数据.根据层次的增加可能会使用递归(类似于读目录树一样)将所有数据写入文件.
------------------------------------
导入文件的过程:
打开相应文件,
依照上面保存的方法得到树结构节点数,然后使用导入数的过程,为它们分配指针,填充适当的数据.
记住:在程序退出时,要记得释放为每一个节点分配的指针.其实这个做法和TREEVIEW的SAVETOFILE差不多,但是是以二进制保存,而且相当于使用一个自己定义结构的数据表.
这个虽然不是依照上面意思所做的工作,但是有些类似.
他简单在层次固定,数据格式固定,但是如果要修改,照上面的结构也很容易,如果你愿意告诉我你想记录你的什么样的树图,我可以写源码给你.
//这一段是把文件读出,形成树
procedure TForm1.Button3Click(Sender: TObject);
Var
 F:Integer;
 i,j:integer;
 CurrentNode:TTreeNode;
 ChildNode:TTreeNode;
 ChildCount:integer;
 Nowx,Nowy:integer;
begin
 TreeView1.Items.Clear ;
 F:=FileOpen('main.RGN',fmOpenRead);
 if F<0 then exit;
 FileRead(F,RegionCount,sizeof(integer));
 for i:=1 to RegionCount do begin
   FileRead(F,childcount,sizeof(integer));
//这一段是记录树的数据.
procedure TForm1.Button2Click(Sender: TObject);
Var
 F:Integer;
 i,j:integer;
 CurrentNode:TTreeNode;
 ChildNode:TTreeNode;
 ChildCount:integer;
begin
 F:=FileCreate('main.RGN');
 if F<0 then exit;
 Filewrite(F,RegionCount,sizeof(integer));
 CurrentNode:=TreeView1.Items.GetFirstNode;
 for i:=1 to RegionCount do begin
   Childcount:=currentNode.Count ;
   Filewrite(F,ChildCount,sizeof(integer));
   FileWrite(F,PPoint(CurrentNode.data)^.x,sizeof(integer));
   FileWrite(F,PPoint(CurrentNode.data)^.y,sizeof(integer));
   ChildNode:=CurrentNode.getFirstChild ;
   for j:=0 to CurrentNode.Count-1 do begin
      fileWrite(F,PPoint(ChildNode.data)^.x,sizeof(integer));
      FileWrite(F,PPoint(ChildNode.data)^.y,sizeof(integer));
      ChildNode:=childNode.getNextSibling;
   end;
   CurrentNode:=CurrentNode.getNextSibling ;
 end;
 FileClose(F);
end;
   Fileread(F,Nowx,sizeof(integer));
   FileRead(F,Nowy,sizeof(integer));
   CurrentNode:=TreeView1.Items.Add(nil,format('x:%d,y:%d',[Nowx,nowy]));
   for j:=0 to ChildCount-1 do begin
     Fileread(F,Nowx,sizeof(integer));
     FileRead(F,Nowy,sizeof(integer));
     childNode:=TreeView1.items.Addchild(CurrentNode,format('x:%d,y:%d',[Nowx,nowy]));
   end;
 end;
 FileClose(F);
end;