gpt4 book ai didi

delphi - 如何防止 TTreeView 的自定义树节点数据丢失?

转载 作者:行者123 更新时间:2023-12-03 14:52:26 25 4
gpt4 key购买 nike

我正在使用Zarko Gajic's Store More (Custom) Data Into The Tree Node Of A Tree View为每个节点项添加额外的字符串,但我发现如果我的应用程序闲置了很长时间,我存储在自定义树节点中的值就会消失。

这就是我昨天离开时我的自定义树节点的样子

Before going home

这就是今天早上的样子(注意 fMyProperty 值现在为空)

Back the next day

我已确认我的计算机从不休眠或 sleep ,但系统会在锁定 1 分钟后关闭显示器以节省电量。然而,计算机需要闲置一段时间才会出现此问题。当整夜闲置时,这种情况最为明显,但如果仅闲置 30 分钟,则不太可能发生。

我能想到的唯一可能导致此问题的原因是操作系统正在将应用程序内存交换到磁盘,并且当您重新激活计算机时,它会交换回内存。正如您所看到的,FItemId 正在发生变化,因此它似乎正在“重建”Treeview,从而失去了与自定义 Tree 节点的关联。

我用一个非常简单的应用程序重现了这个问题,其代码如下。

我知道我可以使用另一种方法来存储附加数据,即使用 Treenode 中的数据字段,但能够做到这一点会很好,因为我不必担心释放附加内存块节点被删除。

我可以采取什么措施来防止发生这种数据丢失?

unit Test04Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls;

type
TMyTreeNode = class(TTreeNode)
private
fMyProperty : string;
public
property MyProperty : string read fMyProperty write fMyProperty;
end;
TForm1 = class(TForm)
TreeView1: TTreeView;
StatusBar1: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
private
fTreeView1_Selected: TMyTreeNode;
property TreeView1_Selected : TMyTreeNode read fTreeView1_Selected;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
tn : TTreeNode;
cnt : integer;
begin
//fill some items
TreeView1.Items.Clear;

for cnt := 0 to 9 do
begin
tn := TreeView1.Items.AddChild(nil, IntToStr(cnt));
//add default MyProperty values
TMyTreeNode(tn).MyProperty := 'this is node ' + IntToStr(cnt);
end;
end;

procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
fTreeView1_Selected := TMyTreeNode(Node);
StatusBar1.Panels[0].Text := TreeView1_Selected.MyProperty;
end;

procedure TForm1.TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
begin
NodeClass := TMyTreeNode;
end;

end.

在Windows 2012 R2上使用Delphi XE6,调试Win32构建,但Win64构建也会出现此问题。

最佳答案

发生这种情况是因为 VCL 窗口重新创建。 VCL设计意味着在某些情况下,需要重新创建实现窗体和控件的窗口。通常,当状态更改无法应用于已存在的窗口时,就会发生这种情况。所以窗口被重新创建。发生这种情况时,控件会尝试保存其状态,然后恢复它。

对于 TreeView ,节点本身被销毁然后重新创建。这意味着在引用节点时需要格外小心。一旦窗口重新创建,该节点引用就无效。

您可以通过调用 TreeView 控件的 protected RecreateWnd 方法来强制执行此操作。您需要 protected 成员访问黑客才能做到这一点。但是,一旦您调用 RecreateWnd,您就可以观察到自定义节点的属性已被清除。实际上,将重写的构造函数和析构函数添加到节点类中,并观察它们在重新创建期间被调用。

你在这里几乎被难住了。据我所知,存储然后恢复节点状态的 TreeView 重新创建代码没有任何钩子(Hook)。您的自定义节点将被销毁,并将被重新创建。我认为没有简单的方法可以让您在此过程中保持节点的状态。 Data 属性会被保留,因此您可以使用它来确保正确地重新创建自定义节点。但是一旦您沿着这条路走下去,自定义节点会提供什么好处?

我的建议是您使用 Data 作为自定义数据,并避免使用自定义节点类型。

据我所知,这个问题使得自定义节点类型功能几乎毫无用处。

关于delphi - 如何防止 TTreeView 的自定义树节点数据丢失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29789773/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com