如何将保存的树(在文件中)作为子树添加到另一棵树?
How to add a saved tree (in a file) to another tree as a subtree?
有什么方法可以将本地存储的(在文件中)TVirtualStringTree
添加到另一个作为特定节点下的子树?
在例子中,为了速度,我使用了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. }
这非常适合这种情况,因为我需要将之前保存的树添加到特定节点(示例中选定的节点)。但是我在网上找不到任何关于它的信息,也找不到它的实际例子。那么如何将已保存的树(其所有内容)恢复为所选节点下的子树?
为了将虚拟树的特定节点及其子节点存储到文件中,您必须使用方法 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;
编辑:已解决,需要添加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),所以我拿出来了
有什么方法可以将本地存储的(在文件中)TVirtualStringTree
添加到另一个作为特定节点下的子树?
在例子中,为了速度,我使用了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. }
这非常适合这种情况,因为我需要将之前保存的树添加到特定节点(示例中选定的节点)。但是我在网上找不到任何关于它的信息,也找不到它的实际例子。那么如何将已保存的树(其所有内容)恢复为所选节点下的子树?
为了将虚拟树的特定节点及其子节点存储到文件中,您必须使用方法 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;
编辑:已解决,需要添加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),所以我拿出来了