在Delphi中将TTreeNode子类化的问题 [英] problem subclassing TTreeNode in delphi

查看:101
本文介绍了在Delphi中将TTreeNode子类化的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个在对接面板上使用TTreeView的delphi 2009应用程序。

i'm writing a delphi 2009 app that uses a TTreeView on a docking panel.

我看到,如果我将TTreeNode子类化,我可以在我的应用程序中进行大幅简化。

i saw i could make big simplifications in my app if i subclassed the TTreeNode. the tree view it's on is placed on a docking panel.

TInfoTreeNode=class(TTreeNode)
private
  // remember some stuff
public
end;

procedure TfraInfoTree.tvInfoCreateNodeClass(Sender: TCustomTreeView;
  var NodeClass: TTreeNodeClass);
begin
  NodeClass:=TInfoTreeNode;
end;

我认为我碰到了墙,但是...每个 TInfoTreeNode实例都需要记住一些事情关于自己。因为在包含TTreeView的面板自动隐藏时释放了句柄,所以这些类被销毁了。

i think i've hit a wall though...each "TInfoTreeNode" instance needs to remember things about itself. since the handles are freed when the panel containing the TTreeView auto-hides, the classes are destroyed.

这是一个问题,因为然后所有这些类所知道的东西都被遗忘了。

that's a problem because then everything the classes knew is then forgotten.

有没有办法解决(除了再次从数据库重新加载每个TInfoTreeNode之外)?

is there a way around this (other than reloading every TInfoTreeNode from the database again)?

谢谢! / p>

thank you!

推荐答案

谢谢大家的答复!

我要10使用TTreeNode的data属性使用树视图已有30年历史了。我想摆脱:

i have for 10 years been using the tree view using TTreeNode's data property. i wanted to be free of:


  • 设置数据属性

  • 创建/销毁数据 对象,因此不会发生内存泄漏

我过去也使用Data属性作为ID号。

i have used the Data property for an ID number in the past as well.

今天,我的节点具有GUID在数据库中查找其数据,因此它们不再适合 Data属性。

today, my nodes have GUIDs to find their data in the database so they don't "fit" into the Data property anymore.

使用TTreeNode的后代似乎很好地满足了我的愿望,但是为了使该工作很好,我不得不做一些事情:

using a descendant of TTreeNode seems to have addressed my wishes nicely but in order to make that work nicely i had to do a few things:


  • 处理TTreeView.OnCreateNodeClass事件

  • 处理TTreeView.OnDeletion事件以在节点被销毁之前检索最新数据

  • 将TTreeView.OnAddition事件处理为:1)维护节点的简单列表2)设置节点的Data属性,以便我们可以使用它在分配用于存储其数据的列表中查找位置。

这是代码:

  TInfoTreeNodeMemory=record
    ...
  end;

  TInfoTreeNode=class(TTreeNode)
  private
    m_rInfoTreeNodeMemory:TInfoTreeNodeMemory;
  public
    property InfoTreeNodeMemory:TInfoTreeNodeMemory read m_rInfoTreeNodeMemory write m_rInfoTreeNodeMemory;
  end;

  TInfoTreeNodeMemoryItemList=class
  private
    m_List:TList<TInfoTreeNodeMemory>;
  public
    constructor Create;
    destructor Destroy; override;

    procedure HandleOnDeletion(Node: TInfoTreeNode);
    procedure HandleOnAddition(Node: TInfoTreeNode);
  end;

  TfraInfoTree = class(TFrame)
    tvInfo: TTreeView;
    procedure tvInfoCreateNodeClass(Sender: TCustomTreeView;
      var NodeClass: TTreeNodeClass);
    procedure tvInfoDeletion(Sender: TObject; Node: TTreeNode);
    procedure tvInfoAddition(Sender: TObject; Node: TTreeNode);
  private
    m_NodeMemory:TInfoTreeNodeMemoryItemList;
   ...

procedure TfraInfoTree.tvInfoCreateNodeClass(Sender: TCustomTreeView;
  var NodeClass: TTreeNodeClass);
begin
  // THIS IS VITAL!
  NodeClass:=TInfoTreeNode;
end;

procedure TfraInfoTree.tvInfoDeletion(Sender: TObject; Node: TTreeNode);
begin
  m_NodeMemory.HandleOnDeletion(TInfoTreeNode(Node));
end;

procedure TfraInfoTree.tvInfoAddition(Sender: TObject; Node: TTreeNode);
begin
  m_NodeMemory.HandleOnAddition(TInfoTreeNode(Node));
end;

g_icTreeNodeNotInList=MAXINT;

procedure TInfoTreeNodeMemoryItemList.HandleOnDeletion(Node: TInfoTreeNode);
var
  iPosition:integer;
begin
  iPosition:=integer(Node.Data);

  if iPosition=g_icTreeNodeNotInList then
    raise Exception.Create('Node memory not found!')
    else
    // we recognize this node; store his data so we can give it back to him later
    m_List[iPosition]:=Node.InfoTreeNodeMemory;
end;

procedure TInfoTreeNodeMemoryItemList.HandleOnAddition(Node: TInfoTreeNode);
var
  iPosition:integer;
begin
  // "coat check" for getting back node data later
  iPosition:=integer(Node.Data);

  if iPosition=g_icTreeNodeNotInList then
    begin
      // Node.Data = index of it's data
      // can't set Node.Data in OnDeletion so we must assign it in OnAddition instead
      Node.Data:=pointer(m_List.Count);
      // this data may very well be blank; it mostly occupies space; we harvest the real data in OnDeletion
      m_List.Add(Node.InfoTreeNodeMemory);
    end
    else
    // we recognize this node; give him his data back
    Node.InfoTreeNodeMemory:=m_List[iPosition];
end;

很酷...它满足了我的所有目标!

very cool...it meets all my objectives!

向树中添加节点,我要做的就是:

to add a node to the tree, all i need to do is:

// g_icTreeNodeNotInList important so the "coat check" (TInfoTreeNodeMemoryItemList)
// can recognize this as something that's not in it's list yet.
MyInfoTreeNode:=TInfoTreeNode(tvInfo.Items.AddChildObject(nParent, sText, pointer(g_icTreeNodeNotInList))));

这篇关于在Delphi中将TTreeNode子类化的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆