如何将保存的树(在文件中)添加到另一棵树作为子树?

时间:2018-10-02 02:34:03

标签: delphi virtualtreeview

有什么方法可以将本地存储(在文件中)TVirtualStringTree作为特定节点下的子树添加到另一个文件中?

EXAMPLE

在示例中,为了速度起见,我使用了TTreeView,但是我需要使用TVirtualStringTree。我试图找到有关此方法的一些信息。

{ TBaseVirtualTree.AddFromStream Method
  Adds the content from the given stream to the given node. }
procedure AddFromStream(Stream: TStream; TargetNode: PVirtualNode);
{ Description
  AddFromStream restores the subtree stored in Stream and adds it to 
  TargetNode. The content of the stream must have been saved previously with 
  SaveToStream. }

哪种情况最合适,因为我需要将先前保存的树添加到特定节点(在示例中为选定的树)。但是我在网上找不到任何有关它的信息,也没有实际的例子。那么如何将已保存的树(其所有内容)还原为所选节点下的子树?

2 个答案:

答案 0 :(得分:1)

要将特定节点及其虚拟树的子节点存储到文件中,必须使用方法SaveToStream,该方法不同于SaveToFile接受源节点的可选参数:

procedure SaveNodeToFile(ATree: TBaseVirtualTree; ANode: PVirtualNode; 
  AFileName: String);
var
  stream: TFileStream;
begin
  stream := TFileStream.Create(AFileName, fmCreate);
  try
    ATree.SaveToStream(stream, ANode);
  finally
    stream.Free;
  end;
end;

由于虚拟树对数据一无所知,因此必须提供一种方法来写入分配给每个节点的数据。树为此提供了事件OnSaveNode。在这里,我假设节点在包含字符串“ Caption”的记录中有数据(或者,当然,您必须根据需要对其进行调整):

type
  PTreeData = ^TTreeData;
  TTreeData = record
    Caption: String;
  end;

procedure TForm1.VirtualStringTree1SaveNode(Sender: TBaseVirtualTree; 
  ANode: PVirtualNode; Stream: TStream);
var
  data: PTreeData;
  n: Integer;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(ANode);
  // Write the length of the string (in characters)
  n := Length(data^.Caption);
  Stream.WriteDWord(n);
  if n > 0 then
    // write the string characters
    Stream.Write(data^.Caption[1], Length(data^.Caption) * SizeOf(char));
end;

为了将文件读回到另一棵树的节点,您已经提到的方法AddFromStream是完美的:

procedure LoadNodeFromFile(ATree: TBaseVirtualTree; ANode: PVirtualNode; AFileName: String);
var
  stream: TFileStream;
begin
  stream := TFileStream.Create(AFileName, fmOpenRead);
  try
    ATree.AddFromStream(stream, ANode);
  finally
    stream.Free;
  end;
end;

同样,您需要告诉树如何获取分配给每个节点的数据-事件OnLoadNode的处理程序必须与OnSaveNode事件完全相反:

procedure TForm1.VirtualStringTree2LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode; 
  Stream: TStream);
var
  data: PTreeData;
  n: DWord;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(Node);
  // Read the string length (in characters)
  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the string
    SetLength(data^.Caption, n);
    if n > 0 then
      // Read the string's characters
      Stream.Read(data^.Caption[1], n * SizeOf(char));
  end;
end;    

答案 1 :(得分:0)

EDIT :已解决,需要添加getnodedatasize事件:

procedure TfrmBuilder.VST1GetNodeDataSize(Sender: TBaseVirtualTree;
  var NodeDataSize: Integer);
begin
   NodeDataSize := SizeOf(TTreeData);
end;

没有树就不会加载。

谢谢


我要重新打开这个主题,还有另一个问题,就是:

我可以使用包含字符串的两列来完美地保存和加载:

type
  PTreeData = ^TTreeData;
  TTreeData = record
  Fname: String;
  quant: String;
End;

procedure TfrmBuilder.VST1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  data: PTreeData;
  n: DWord;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(Node);

  // Read the string length (in characters)
  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the string
    SetLength(data^.Fname, n);
    if n > 0 then
      // Read the string's characters
      Stream.Read(data^.Fname[1], n * SizeOf(char));
  end;

  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the second string
    SetLength(data^.quant, n);
    if n > 0 then
      // Read the second string's characters
      Stream.Read(data^.quant[1], n * SizeOf(char));
  end;

end;

procedure TfrmBuilder.VST1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  data: PTreeData;
  n: Integer;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(Node);

  // Write the length of the string (in characters)
  n := Length(data^.Fname);
  Stream.WriteDWord(n);
  if n > 0 then
    begin
    // write the string characters
    Stream.Write(data^.Fname[1], Length(data^.Fname) * SizeOf(char));
    end;

  // Write the length of the second string (in characters)
  n := Length(data^.quant);
  Stream.WriteDWord(n);

  if n > 0 then
    begin
    // write the second string chars
    Stream.Write(data^.quant[1], Length(data^.quant) * SizeOf(char));
    end;

end;

但是,当我尝试使用相同的方法(将字符串写入流中)保存三列时,它将在可执行文件的第一次运行时加载,但是当我关闭exe时,请重新打开并尝试执行重新加载它会给出一个错误sisegv,换句话说就是内存访问冲突

type
  PTreeData = ^TTreeData;
  TTreeData = record
  Fname: String;
  quant: String;
  OBS: string;

End;

procedure TfrmBuilder.VST1LoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  data: PTreeData;
  n: DWord;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(Node);

  // Read the string length (in characters)
  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the string
    SetLength(data^.Fname, n);
    if n > 0 then
      // Read the string's characters
      Stream.Read(data^.Fname[1], n * SizeOf(char));
  end;

  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the second string
    SetLength(data^.quant, n);
    if n > 0 then
      // Read the second string's characters
      Stream.Read(data^.quant[1], n * SizeOf(char));
  end;

  { THE CODE FOR THE THIRD STRING: 
  n := Stream.ReadDWord;
  if n > 0 then begin
    // Set the length of the THIRD string
    SetLength(data^.OBS, n);
    if n > 0 then
      // Read the THIRD string's characters
      Stream.Read(data^.OBS[1], n * SizeOf(char));
  end;
  }
end;

procedure TfrmBuilder.VST1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
var
  data: PTreeData;
  n: Integer;
begin
  // Get pointer to the node's data
  data := Sender.GetNodeData(Node);

  // Write the length of the string (in characters)
  n := Length(data^.Fname);
  Stream.WriteDWord(n);
  if n > 0 then
    begin
    // write the string characters
    Stream.Write(data^.Fname[1], Length(data^.Fname) * SizeOf(char));
    end;

  // Write the length of the second string (in characters)
  n := Length(data^.quant);
  Stream.WriteDWord(n);

  if n > 0 then
    begin
    // write the second string chars
    Stream.Write(data^.quant[1], Length(data^.quant) * SizeOf(char));
    end;

  { 
  // Write the length of the THIRD string (in characters)
  n := Length(data^.OBS);
  Stream.WriteDWord(n);

  if n > 0 then
    begin
    // write the THIRD string chars
    Stream.Write(data^.OBS[1], Length(data^.OBS) * SizeOf(char));
    end;
   }
end;

可能是什么?对于2个字符串(2列),它就像一个符咒,但是对于三个字符串,我却出现访问冲突?

预先感谢, 莱昂纳多

PS:我正在尝试保存/加载的网格图片

grid

如图所示,它有两列,第一列来自data ^ .fname,第二列来自data ^ .quant,第三列应该来自data ^ .OBS,但它只是没有加载(sigsegv),所以我选择了出来。