The Delphi Bug List

Entry No.
545
VCL - Win32 - ComCtrls - TTreeView
Changing the parent of a TreeView makes it lose the content of its HasChildren field
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 4.03 5.0 5.01 6.0 6.01 6.02 Kylix 1.0
N/AExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsN/A
Description
Reported by Hans Voogt; checked by Reinier Sterkenburg
According to the help file (TControl.Parent):

Changing the parent of a control moves the control onscreen so that it is displayed within the parent.

If you happen to do this with a TTreeView of which you have set the Property HasChildren of 1 or more nodes, the value of this property will be lost.

Source code example:
Form with 2 panels, on Panel1 a TTreeview with Align = alClient.
Upon running, Treeview1 will display the root node and his 10 children, all with a '+'. Should be so because HasChildren is set to true.
Change the parent by clicking Button1 and the + signs of the children will disappear.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    TreeView1: TTreeView;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
  Root: TTreeNode;
begin
  Root := TreeView1.Items.Add(nil, 'Root');                // Add root node
  for i := 0 to 9 do
    with TreeView1.Items.AddChild(Root, IntToStr(i)) do    // Add 10 children
      HasChildren := True;                                 // Make '+' appear
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TreeView1.Parent := Panel2;                              // Switch Parents
end;

end.
Cause
: Upon looking at the source code (comctrls) of TTreeNode I found that in TTreenode.ReadData & TTreeNode.WriteData HasChildren is not read/written. Comparing the code with TTreeNode.Assign shows that 2 more properties are not read/written by the reader/writer: Cut and DropTarget (Focus also doesn't get read/written but I can see the logic in that).
Solution / workaround
To work around this problem you have to add HasChildren (and, if you're interested, Cut & DropTarget) to TTreeNode.ReadData, TTreeNode.WriteData and of course to TNodeInfo (packed record for TTreeNode). (See Code Below).

changes to Comctrls.pas:
========================

  TNodeInfo = packed record
    ImageIndex: Integer;
    SelectedIndex: Integer;
    StateIndex: Integer;
    OverlayIndex: Integer;
    Data: Pointer;
    Count: Integer;
    HasChildren: Boolean;                                  // New line 
    Text: string[255];
  end;

procedure TTreeNode.ReadData(Stream: TStream; Info: PNodeInfo);
var
  I, Size, ItemCount: Integer;
begin
  Owner.ClearCache;
  Stream.ReadBuffer(Size, SizeOf(Size));
  Stream.ReadBuffer(Info^, Size);
  Text := Info^.Text;
  ImageIndex := Info^.ImageIndex;
  SelectedIndex := Info^.SelectedIndex;
  StateIndex := Info^.StateIndex;
  OverlayIndex := Info^.OverlayIndex;
  HasChildren := Info^.HasChildren;                        // New Line
  Data := Info^.Data;
  ItemCount := Info^.Count;
  for I := 0 to ItemCount - 1 do
    Owner.AddChild(Self, '').ReadData(Stream, Info);
end;

procedure TTreeNode.WriteData(Stream: TStream; Info: PNodeInfo);
var
  I, Size, L, ItemCount: Integer;
begin
  L := Length(Text);
  if L > 255 then L := 255;
  Size := SizeOf(TNodeInfo) + L - 255;
  Info^.Text := Text;
  Info^.ImageIndex := ImageIndex;
  Info^.SelectedIndex := SelectedIndex;
  Info^.OverlayIndex := OverlayIndex;
  Info^.StateIndex := StateIndex;
  Info^.Data := Data;
  Info^.HasChildren := HasChildren;                        // New Line
  ItemCount := Count;
  Info^.Count := ItemCount;
  Stream.WriteBuffer(Size, SizeOf(Size));
  Stream.WriteBuffer(Info^, Size);
  for I := 0 to ItemCount - 1 do Item[I].WriteData(Stream, Info);
end;
Latest update of this entry: 2002-04-07

Post a comment on this bug


Index page
Delphi Bug List home page
The Delphi Bug Lists are presently maintained by Jordan Russell, who has taken over this task from Reinier Sterkenburg since August 2000.
All feedback is appreciated. See also the feedback section of the Delphi Bug List home page.