TAdvTreeView - reparenting nodes

Hi,

I was wondering if there is any built in facility to reparent a node once it's been added to the treeview?

I have a requirement, whereby if a node [N] only has one child [C] with a particular value, all of C's  children need to be moved to be children of the original node [N], and then C deleted.

Because the tree is built dynamically as I loop around a query, I don't know until the tree is fully built whether the 'move' criteria will apply, so I need to do this after the tree is built, rather than checking during the build process.

I am in the process of writing code to achieve this, simply by looping through C's children, creating new children for N with the same properties, then deleting from C,  but I was wondering if there is an easier built in way to just say something like, for example Cn.Parent:=N; [where Cn is each child of C]

Hi, 


Yes you should be able to use the following code to reparent:


AdvTreeView1.Nodes[1].MoveTo(AdvTreeView1.Nodes[0].Nodes[0]);


You can use this code to move nodes from any level along with it's children to any other level inside the treeview as long as it's not corrupting the hierarchy. What I mean with this is that the Node isn't moved to one of its own children or to itself.

Thanks, Pieter. MoveTo() is just what I needed! 

Hi Pieter,

I don't think that the 'DataXXXX' properties of the Node.Values[] property is being set when a node is moved using MoveTo()  Before the MoveTo(), I have some non-zero value in Node.Values[1].DataInteger, but after the MoveTo(), the value is zero.

I haven't checked the other DataXXXX properties as I don't use them, but DataInteger isn't being set.
Are you using the latest version? We have tested this here and the Data* properties are being transfered correctly. Please note that if you are using the MoveTo, the node is added at the last position, if you do not specify the index parameter. Additionally, you need to re-access the nodes collection and verify if the Data properties are assigned. If you have troubles with this, please send us your code snippet that shows invalid Data properties so we can investigate here what exactly is going wrong?
Hi Pieter,

Have just downloaded and checked with the latest version (1.1.4.10) and still having the problem.

Add a TAdvTreeview to a blank form, with 3 buttons.

To initialise the treeview, add the following code to Button1Click


procedure TForm9.Button1Click(Sender: TObject);
var TmpNode: TAdvTreeviewNode;
begin

  with AdvTreeview1 do
  begin

    ClearNodes;
    ClearColumns;

    Columns.Add.Text:='Nodes';
    Columns.Add.Text:='Data';

    { top level }
    TmpNode:=Nodes.Add;
    with TmpNode do
    begin
      Text[0]:='Level 0';
      DataInteger:=1;
      Text[1]:='101';
      Values[1].DataInteger:=101;
    end;

    { second level }
    TmpNode:=TmpNode.Nodes.Add;
    with TmpNode do
    begin
      Text[0]:='Level 1';
      DataInteger:=2;
      Text[1]:='102';
      Values[1].DataInteger:=102;
    end;

    { third level - 3 nodes }
    with TmpNode.Nodes.Add do
    begin
      Text[0]:='Level 2a';
      DataInteger:=3;
      Text[1]:='103';
      Values[1].DataInteger:=103;
    end;

    with TmpNode.Nodes.Add do
    begin
      Text[0]:='Level 2b';
      DataInteger:=4;
      Text[1]:='104';
      Values[1].DataInteger:=104;
    end;

    with TmpNode.Nodes.Add do
    begin
      Text[0]:='Level 2c';
      DataInteger:=5;
      Text[1]:='105';
      Values[1].DataInteger:=105;
    end;

  end;

end;


To reparent the level 2 nodes, add the following code to Button2Click

[code]

procedure TForm9.Button2Click(Sender: TObject);
var NewParent,OldParent:TAdvTreeviewNode; var N:integer;
begin

with AdvTreeview1 do
begin

NewParent:=Nodes[0];
OldParent:=Nodes[0].Nodes[0];

for N:=OldParent.GetChildCount-1 downto 0 do
begin
  OldParent.Nodes[N].MoveTo(NewParent,0);
end;

OldParent.Free;

end;

end;

{/CODE]

Finally, to see the values of DataInteger, add the following code to Button3Click

procedure TForm9.Button3Click(Sender: TObject);
var S1,S2:string; Node:TAdvTreeviewNode;
begin

  with AdvTreeview1 do
  begin

    S1:=''; S2:='';

    Node:=GetFirstRootNode;
    while Node<>NIL do
    begin
      S1:=S1+Node.DataInteger.ToString+' ';
      S2:=S2+Node.Values[1].DataInteger.ToString+' ';
      Node:=Node.GetNext;
    end;

    ShowMessage(S1+#13+S2);

  end;

end;

Click Button1 to init the treeview.
Click Button3 to see the DataInteger values, should see
1 2 3 4 5
101 102 103 104 105

Click Button2 to reparent the level 2 nodes to the top level node and delete the original parent.
Click Button3 to see the DataInteger values: expecting:
1 3 4 5
101 103 104 105

Actually get:
1 3 4 5
101 0 0 0

The Node.Values[1].DataInteger value is getting lost during the reparent
The Node.DataInteger value is ok!



Hi, 


Thanks for the sample, we have applied a fix, the next version will address this.

Could you send an incremental source update, or if it's a simple fix, let me know what changes I need to make to the code. Thanks,

In AdvTreeViewData.pas you need to change the code to:




procedure TAdvTreeViewNodeValue.Assign(Source: TPersistent);
begin
  if Source is TAdvTreeViewNodeValue then
  begin
    FTag := (Source as TAdvTreeViewNodeValue).Tag;
    FText := (Source as TAdvTreeViewNodeValue).Text;
    FCheckType := (Source as TAdvTreeViewNodeValue).CheckType;
    FChecked := (Source as TAdvTreeViewNodeValue).Checked;
    FCollapsedIcon.Assign((Source as TAdvTreeViewNodeValue).CollapsedIcon);
    FCollapsedIconLarge.Assign((Source as TAdvTreeViewNodeValue).CollapsedIconLarge);
    FExpandedIcon.Assign((Source as TAdvTreeViewNodeValue).ExpandedIcon);
    FExpandedIconLarge.Assign((Source as TAdvTreeViewNodeValue).ExpandedIconLarge);
    FCollapsedIconName := (Source as TAdvTreeViewNodeValue).CollapsedIconName;
    FCollapsedIconLargeName := (Source as TAdvTreeViewNodeValue).CollapsedIconLargeName;
    FExpandedIconName := (Source as TAdvTreeViewNodeValue).ExpandedIconName;
    FExpandedIconLargeName := (Source as TAdvTreeViewNodeValue).ExpandedIconLargeName;
    AssignData(Source);
  end;
end;


procedure TAdvTreeViewNodeValue.AssignData(Source: TPersistent);
begin
  if Source is TAdvTreeViewNodeValue then
  begin
    FDataString := (Source as TAdvTreeViewNodeValue).DataString;
    FDataPointer := (Source as TAdvTreeViewNodeValue).DataPointer;
    FDataBoolean := (Source as TAdvTreeViewNodeValue).DataBoolean;
    FDataObject := (Source as TAdvTreeViewNodeValue).DataObject;
    FDataInteger := (Source as TAdvTreeViewNodeValue).DataInteger;
    FDBKey := (Source as TAdvTreeViewNodeValue).DBKey;
  end;
end;

Thanks Pieter, all ok now.

Great !