2

假设我有这个节点数据记录:

Type
  PPerson = ^TPerson;
  TPerson = record
   Name: String;
   Age: Integer;
   SomeBool: Boolean;
  end;

要填充我的 VirtualStringTree,我会这样做:

Procedure AddToTree(Person: TPerson);
Var
 Node: PVirtualNode;
 Data: PPerson;
Begin
 Node := VT.AddChild(nil);
 Data := VT.GetNodeData(Node);
 Data.Name := Person.Name;
 Data.Age  := Person.Age;
 Data.SomeBool := Person.SomeBool;
End;

Procedure TMyForm.MyButtonClick(Sender: TObject);
Var
 Person: TPerson;
Begin
 Person.Name := 'Jeff';
 Person.Age := 16;
 Person.SomeBool := False;
 AddToTree(Person);

End:

现在,虽然这工作得很好,但我想简化它,所以每当我向记录添加新字段时,我都不会修改 AddToTree 方法。

所以我尝试了这个:

Procedure AddToTree(Person: TPerson);
Begin
 VT.AddChild(nil,@Person);
End;

这可以编译,似乎PVirtualNode没有获取数据,因为我的 VT 没有显示任何内容,并且在中断 OnGetText 事件时,我看到变量为空。

我究竟做错了什么?:)

4

4 回答 4

5

记录支持赋值运算符:

procedure AddToTree(const Person: TPerson);
var
  Node: PVirtualNode;
  Data: PPerson;
begin
  Node := VT.AddChild(nil);
  Data := VT.GetNodeData(Node);
  Data^ := Person;
end;
于 2011-08-05T20:21:32.200 回答
3

您没有阅读手册:)

好的,在这种情况下,来源是手册 - 引用AddChild()来源:

UserData 可用于将用户数据区的前 4 个字节设置为可在 OnInitNode 中使用的初始值,即使该节点尚未“正式”,也会触发 OnFreeNode 事件(如果 <> nil)初始化。

IOW 它并不意味着以您使用它/期望它工作的方式使用。

顺便说一句,你为什么要复制数据?为什么没有

type
  PTreeData = ^TTreeData;
  TTreeData = record
   Data: PPerson;
  end;

并分配记录New()并将它们保留在树中,然后Dispose()在清除树时?

于 2011-08-05T18:58:57.357 回答
3

将记录用作数据持有者时,在 VTV 中存储数据的最佳方式是仅存储指向记录的指针,而记录本身则单独存储在列表/数组中。当可视组件实际上不拥有数据时,这也对应于虚拟和 MVC 范式。IOW,添加记录的方案是:

  • 使用 AllocMem, New, ... 为记录 (!) 分配内存
  • 填写其字段
  • 将其添加到列表/数组
  • 使用 NodeData = PNewRecord 将新节点添加到 VTV

删除记录的方案是:

  • 从 VTV 中删除对应的节点
  • 使用 Finalize (!) 完成记录,从而避免引用计数字段的内存泄漏
  • 使用 FreeMem、Dispose、... 释放分配的内存
  • 从列表/数组中删除项目
于 2012-09-25T14:42:43.953 回答
0

还有一个“我在问这个问题后 2 分钟找到了答案”——多么丢脸…… :(

无论如何,所以 - 这可以通过使用 CopyMemory 来完成,如下所示:

Procedure AddToTree(Person: TPerson);
Var
 Data: PPerson;
 Node: PVirtualNode;
Begin
 // add node
 Node := VT.AddChild(nil);
 // Get data of the node
 Data := VT.GetNodeData(Node);
 // Copy the Person stuff to the Node's data.
 CopyMemory(Data,@Person,SizeOf(Person));
End;
于 2011-08-05T18:58:08.310 回答