将数据写入PVirtualNode,无需手动设置各个字段值

发布于 2024-11-28 13:06:41 字数 939 浏览 1 评论 0原文

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

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事件时,我看到变量是空的。

我做错了什么? :)

Lets say I have this node data record:

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

To populate my VirtualStringTree, I would do this:

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:

Now, while this works perfectly fine, I would like to simplify it, so whenever I add new fields to the record, I wont have modify the AddToTree method.

So I tried this:

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

This compiles, but it appears the PVirtualNode did not get the data, because my VT is not displaying anything, and when breaking in the OnGetText event, I see the variables are empty.

What am I doing wrong? :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

醉酒的小男人 2024-12-05 13:06:41

记录支持赋值运算符:

procedure AddToTree(const Person: TPerson);
var
  Node: PVirtualNode;
  Data: PPerson;
begin
  Node := VT.AddChild(nil);
  Data := VT.GetNodeData(Node);
  Data^ := Person;
end;

Records support the assignment operator:

procedure AddToTree(const Person: TPerson);
var
  Node: PVirtualNode;
  Data: PPerson;
begin
  Node := VT.AddChild(nil);
  Data := VT.GetNodeData(Node);
  Data^ := Person;
end;
情深缘浅 2024-12-05 13:06:41

您没有阅读手册 :)

好的,在本例中,来源是手册 - 引用 AddChild() 来源:

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

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

顺便说一句,你为什么要复制数据?为什么不使用

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

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

You aren't reading the manual :)

OK, in this case the source is the manual - quote from the AddChild() source:

UserData can be used to set the first 4 bytes of the user data area to an initial value which can be used
in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
"officially" initialized.

IOW it isn't meant to be used in the way youre using it / expecting it to work.

BTW why do you copy data around? Why not have

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

and allocate records with New() keep them in the tree and then Dispose() when tree is cleared?

丢了幸福的猪 2024-12-05 13:06:41

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

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

以及删除方案一条记录是:

  • 使用 Finalize (!)从 VTV Finalize 记录中删除相应的节点
  • ,从而避免内存泄漏
    引用计数字段
  • 使用 FreeMem、Dispose、... 释放分配的内存
  • 从列表/数组中删除项目

The best way of storing data in VTV when using records as data holders is to store only pointers to the records while records themselves are stored separately in a list/array. This also corresponds to a virtual and MVC paradigm when visual component doesn't actually owns data.
IOW, the scheme of adding a record is:

  • Allocate memory for the record (!) using AllocMem, New, ...
  • Fill its fields
  • Add it to the list/array
  • Add new node to VTV with NodeData = PNewRecord

and the scheme of deleting a record is:

  • Delete corresponding node from VTV
  • Finalize record using Finalize (!) thus avoiding memory leaks with
    ref-counted fields
  • Dispose allocated memory using FreeMem, Dispose, ...
  • Delete item from list/array
梦里的微风 2024-12-05 13:06:41

还有一个“我在问问题后 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;

Yet another "I found the answer 2 minutes after I asked the question" - how humiliating... :(

Anyways, so - this can be acomplished by using CopyMemory, like this:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文