1. Technology

Store More (Custom) Data Into The Tree Node Of A Tree View

TTreeNode.Data AND/OR TTreeView.OnCreateNodeClass

By

The TTreeView Delphi component displays a hierarchical list of items - tree nodes. A node is presented by node text and an optional image. Each node in a tree view is an instance of a TTreeNode class.

While you can fill in the tree view with items at design time, using the TreeView Items Editor, in most cases you would fill your tree view at run time - depending what your application is about.

The TreeView Items Editor reveals there's only a handful of information you can "attach" to a node: text and a few image indexes (for the normal state, expanded, selected and alike).

In essence, the tree view component is easy to program against. There are a couple of methods to add new nodes to the tree and set their hierarchy.

Here's how to add 10 nodes to the tree view (named "TreeView1"). Note that the Items property provides access to all nodes in the tree. The AddChild adds a new node to the tree view. The first parameter is the parent node (to build up the hierarchy) and the second parameter is the node text.

var
  tn : TTreeNode;
  cnt : integer;
begin
  TreeView1.Items.Clear;

  for cnt := 0 to 9 do
  begin
    tn := TreeView1.Items.AddChild(nil, IntToStr(cnt));
  end;
end;
The AddChild returns the newly added TTreeNode. In the above code sample, all 10 nodes are added as root nodes (have no parent node).

In any more complex situations you would want your nodes to carry more info - preferably to have some special values (properties) that are specific to the project you are developing.

Say you want to display customer-order-item data from your database. Each customer can have more orders and each order is made up from more items. This is a hierarchical relation one can display in a tree view:

- Customer_1
  |- Order_1_1
     |- Item_1_1_1
     |- Item_1_1_2
  |- Order_2
     |- Item_2_1
- Customer_2
  |- Order_2_1
     |- Item_2_1_1
     |- Item_2_1_2
In your database there would be more info for each order and for each item. The tree view displays the (read only) current state - and you want to see per order (or even per item) details for the selected order.

When the user selects the node "Order_1_1" you want the order details (total sum, date, etc) to get displayed to the user.

You can, at that time fetch the required data from the database, BUT you would need to know the unique identifier (let's say an integer value) of the selected order to grab the correct data.

We need a way to store this order identifier along with the node but we cannot use the Text property. The custom value we need to store in each node is an integer (just an example).

When such a situation happens you might be tempted to look for the Tag property (many Delphi components have) but the Tag property is not exposed by the TTreeNode class.

Add Custom Data To Tree Nodes - The TreeNode.Data Property

The Data property of a tree node allows you to associate your custom data with a tree node. Data is a pointer and can point to objects and records. The Displaying XML (RSS Feed) Data in a TreeView shows how to store a record type variable into the Data property of a tree node.

Many item-type classes expose the Data property - you can use to store any object along with the item. An example is the TListItem of a TListView component. Here's how to add objects to the Data property.

Add Custom Data To Tree Nodes - The TreeView.CreateNodeClass

If you do not want to use the Data property of the TTreeNode, but rather you would like to have your own TreeNode extended with a few properties, Delphi also has a solution.

Say you want to be able to do

"TreeView1.Selected.MyProperty := 'new value'".
Here's how to extend the standard TTreeNode with a few properties of your own:

  1. Create your TMyTreeNode by extending the TTreeNode.
  2. Add it a string property MyProperty.
  3. Handle the OnCreateNodeClass for the tree view to specify your node class should be created.
  4. Expose something like TreeView1_SelectedNode property on the form level. This would be of type TMyTreeNode.
  5. Handle tree view's OnChange to write to the SelectedNode the value of the node that is selected.
  6. Use TreeView1_Selected.myProperty to read or write new custom value.
Here's the full source code (TButton: "Button1" and TTreeView: "TreeView1" on a form):
unit UnitSample;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls;

type
  TMyTreeNode = class(TTreeNode)
  private
    fMyProperty: string;
  public
    property MyProperty : string read fMyProperty write fMyProperty;
  end;

  TMyTreeNodeForm = class(TForm)
    TreeView1: TTreeView;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
    procedure Button1Click(Sender: TObject);
  private
    fTreeView1_Selected: TMyTreeNode;
    property TreeView1_Selected : TMyTreeNode read fTreeView1_Selected;
  public
    { Public declarations }
  end;

var
  MyTreeNodeForm: TMyTreeNodeForm;

implementation
{$R *.dfm}

procedure TMyTreeNodeForm.Button1Click(Sender: TObject);
begin
  //change the value of MyProperty on some button click
  if Assigned(TreeView1_Selected) then
    TreeView1_Selected.MyProperty := 'new value';
end;

//form OnCreate
procedure TMyTreeNodeForm.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;


//TreeView OnChange
procedure TMyTreeNodeForm.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  fTreeView1_Selected := TMyTreeNode(Node);
end;

//TreeView OnCreateNodeClass
procedure TMyTreeNodeForm.TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
begin
  NodeClass := TMyTreeNode;
end;

end.
This time the Data property of the TTreeNode class is not used. Rather, you extend the TTreeNode class to have your own version of a tree node: TMyTreeNode.

Using the OnCreateNodeClass event of the tree view, you create a node of your custom class instead of the standard TTreenode class.

Finally, if you up to using tree views in your applications, do take a look at the VirtualTreeView.

  1. About.com
  2. Technology
  3. Delphi
  4. Using VCL Components
  5. TTreeView
  6. Delphi: Store More Custom Data Into Tree Node

©2014 About.com. All rights reserved.