Recent

Author Topic: [SOLVED] Check all children of a tree node by number  (Read 459 times)

maurobio

  • Full Member
  • ***
  • Posts: 153
[SOLVED] Check all children of a tree node by number
« on: June 29, 2020, 03:02:28 pm »
Dear ALL,

My problem today is as follows...  :(

I have a TreeView and would like to check programmatically all children of a node, given by its number in the tree.

My lame attempt of writing a procedure for achieving that produced bizarre results:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.CheckNode(NodeNo: integer);
  2. var
  3.   NodeItem: TTreeNode;
  4. begin
  5.   NodeItem := TreeView1.Items[NodeNo];
  6.   if (NodeItem <> nil) then
  7.   repeat
  8.     NodeItem := NodeItem.GetNextSibling;
  9.     NodeItem.StateIndex := Ord(True);
  10.   until (NodeItem = nil);
  11. end;
  12.  
My complete example code is attached.

Could someone give me a hand?

Thanks in advance!

With best wishes,
« Last Edit: July 01, 2020, 11:02:39 pm by maurobio »
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.9.3/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19 ("Tessa"), Windows XP SP3, Windows 7 Professional, Windows 10 Home

ASerge

  • Hero Member
  • *****
  • Posts: 1637
Re: Check all children of a tree node by number
« Reply #1 on: June 29, 2020, 03:23:47 pm »
My lame attempt of writing a procedure for achieving that produced bizarre results:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.CheckNode(NodeNo: integer);
  2. var
  3.   NodeItem: TTreeNode;
  4. begin
  5.   NodeItem := TreeView1.Items[NodeNo];
  6.   if (NodeItem <> nil) then
  7.   repeat
  8.     NodeItem := NodeItem.GetNextSibling;
  9.     NodeItem.StateIndex := Ord(True);
  10.   until (NodeItem = nil);
  11. end;
  12.  
Swap lines 8 and 9.
And the node number is an absolute index of node in the tree, which is usually not convenient for users.

wp

  • Hero Member
  • *****
  • Posts: 7353
Re: Check all children of a tree node by number
« Reply #2 on: June 29, 2020, 03:24:52 pm »
What is the "node number"? There is no such concept.

There is a Node.Index which is the index of a node relative to its parent. So, when a node (no matter where it is located on the tree) has children, the first child hand Index 0, the second child has Index 1 etc.

There is also a Node.Absoluteindex which counts the nodes while they were created and added. Here is part of your code, and I am adding the AbsoluteIndex of each node created:
Code: Pascal  [Select][+][-]
  1.   with TreeView1.Items do
  2.   begin
  3.     pnode := Add(nil, 'Parent1');                        // pNode.AbsoluteIndex = 0
  4.     node := AddChild(pnode, '1. P1Child1');              // node.AbsoltueIndex = 1
  5.     node.StateIndex := Ord(True);
  6.     node := AddChild(pnode, '2. P1Child2');              // node.AbsoluteIndex = 2
  7.     node.StateIndex := Ord(False);
  8.     node := AddChild(pnode, '3. P1Child3');              // node.AbsoluteIndex = 3
  9.     node.StateIndex := Ord(False);
  10.  
  11.     pnode := Add(nil, 'Parent2');                        // pnode.AbsoluteIndex = 4
  12.          
  13.     pnode := Add(nil, 'Parent3');                        // pnode.AbsoluteIndex = 5
  14.     node := AddChild(pnode, '1. P3Child1');              // node.AbsoluteIdnex = 6
  15.     node.StateIndex := Ord(False);
  16.     node := AddChild(pnode, '2. P3Child2');              // node.AbsoluteIndex = 7
  17.     node.StateIndex := Ord(False);
  18.   ...    

You code CheckNode() looks as if you want to check all silblings of a given node. The correct code for this would be:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.CheckAllSiblings(ANode: TTreeNode; Checked: boolean);
  2. begin
  3.   if ANode.Parent = nil then
  4.     exit;
  5.  
  6.   ANode := ANode.Parent.GetFirstChild;
  7.   while ANode <> nil do begin
  8.     ANode.StateIndex := Ord(Checked);
  9.     ANode := ANode.GetNextSibling;
  10.   end;
  11. end;
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

maurobio

  • Full Member
  • ***
  • Posts: 153
Re: Check all children of a tree node by number
« Reply #3 on: June 29, 2020, 03:49:25 pm »
Dear @ASerge and @wp,

Thanks a lot for your suggestions, but I could not see how they address my problem.

What I need is a way to check all the children of a given parent, identified by its (relative?) number in the the tree.

So, I have a tree like:

Parent1
   Child1
   Child2
Parent2
   Child1
   Child2

I would like to have a procedure to check all children of, say, parent number 2 (in this case, the node labelled "Parent2"). It should be similar to the procedure "CheckAllSiblings" suggested by @wp, but using the parent number instead of a given node.

In the complete example I provided, the user inputs a number (of a parent node) and then all its children  should be checked.

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.9.3/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19 ("Tessa"), Windows XP SP3, Windows 7 Professional, Windows 10 Home

jamie

  • Hero Member
  • *****
  • Posts: 3257
Re: Check all children of a tree node by number
« Reply #4 on: June 29, 2020, 04:02:00 pm »
Pick your parent NODE first...

then go into a loop...
Code: Pascal  [Select][+][-]
  1. ANode := GetFirstChild(ParentNode);
  2.  
  3. While ANode <> nil) do
  4.  begin
  5.    /// do something with this Anode;
  6.   ANode := GetNextChild(ParentNode);
  7. End;
  8.  

 You should also be able to use Siblings too but I think that may work a little differently in logic..
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 7353
Re: Check all children of a tree node by number
« Reply #5 on: June 29, 2020, 04:05:28 pm »
Dear @ASerge and @wp,

Thanks a lot for your suggestions, but I could not see how they address my problem.

What I need is a way to check all the children of a given parent, identified by its (relative?) number in the the tree.

So, I have a tree like:

Parent1
   Child1
   Child2
Parent2
   Child1
   Child2

I would like to have a procedure to check all children of, say, parent number 2 (in this case, the node labelled "Parent2"). It should be similar to the procedure "CheckAllSiblings" suggested by @wp, but using the parent number instead of a given node.

In the complete example I provided, the user inputs a number (of a parent node) and then all its children  should be checked.

With best wishes,
Which number would I have to select when I want to pick Parent2? Assuming numbers begin with 0 (which is not self-evident on the GUI side at all!) would it be 1 (because it is the 2nd node at the "parent" level? Or is it 3 (because all nodes at all levels are counted (= AbsoluteIndex)? How are collapsed nodes handled? If they are the user has to expand all nodes to count correctly! How are nodes counted when the first tree node has been scrolled out of the window? If yes I must maybe scroll a huge portion of the screen and count correctly.

I think the concept with node numbers is very confusing. It would be much clearer if you'd introduce a button/menu item/context menu "Check children" to select all children of the currently selected node.
« Last Edit: June 29, 2020, 04:17:18 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

ASerge

  • Hero Member
  • *****
  • Posts: 1637
Re: Check all children of a tree node by number
« Reply #6 on: June 29, 2020, 04:23:16 pm »
mplete example I provided, the user inputs a number (of a parent node) and then all its children  should be checked.
OK. Understand. Add this:
Code: Pascal  [Select][+][-]
  1. function GetNodeAtUpperLevelByIndex(Nodes: TTreeNodes; Index: Integer): TTreeNode;
  2. begin
  3.   if (Nodes = nil) or (Index < 0) then
  4.     Exit(nil);
  5.   Result := Nodes.GetFirstNode;
  6.   while (Index > 0) and (Result <> nil) do
  7.   begin
  8.     Dec(Index);
  9.     Result := Result.GetNextSibling;
  10.   end;
  11. end;
  12.  
  13. procedure SetAllChildStateAsChecked(Parent: TTreeNode);
  14. var
  15.   NodeItem: TTreeNode;
  16. begin
  17.   if Parent = nil then
  18.     Exit;
  19.   NodeItem := Parent.GetFirstChild;
  20.   while NodeItem <> nil do
  21.   begin
  22.     NodeItem.StateIndex := 1;
  23.     NodeItem := NodeItem.GetNextSibling;
  24.   end;
  25. end;

And change:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.TreeView1DblClick(Sender: TObject);
  2. var
  3.   NbrStr: string;
  4.   LParent: TTreeNode;
  5. begin
  6.   NbrStr := InputBox('Input node number', 'Please type in node number to be checked', '0');
  7.   LParent := GetNodeAtUpperLevelByIndex(TreeView1.Items, StrToIntDef(NbrStr, 0) - 1); // ...-1 !
  8.   if LParent <> nil then
  9.     SetAllChildStateAsChecked(LParent);
  10. end;

maurobio

  • Full Member
  • ***
  • Posts: 153
Re: Check all children of a tree node by number
« Reply #7 on: June 29, 2020, 04:35:57 pm »
@ASerge,

Thanks a lot for the updated code. It works fine!  :-[

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.9.3/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19 ("Tessa"), Windows XP SP3, Windows 7 Professional, Windows 10 Home

wp

  • Hero Member
  • *****
  • Posts: 7353
Re: Check all children of a tree node by number
« Reply #8 on: June 29, 2020, 04:39:48 pm »
You can simply call GetFirstChild to get into the children level, and referring to your original code, reverse the StateIndex and GetNextSibling lines, as ASerge already suggested.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.CheckNode(NodeNo: integer);
  2. var
  3.   NodeItem: TTreeNode;
  4. begin
  5.   NodeItem := TreeView1.Items[NodeNo];
  6.   NodeItem := NodeItem.GetFirstChild;
  7.   while (NodeItem <> nil) do
  8.   begin
  9.     NodeItem.StateIndex := Ord(True);
  10.     NodeItem := NodeItem.GetNextSibling;
  11.   end;
  12. end;
« Last Edit: June 29, 2020, 04:41:42 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

maurobio

  • Full Member
  • ***
  • Posts: 153
Re: Check all children of a tree node by number
« Reply #9 on: June 29, 2020, 09:19:25 pm »
@wp,

Thanks for your new suggestion. It would provide a more compact solution, but unfortunately I have not been able to put it to work. No errors, but no checked children either.

Anyway, I got it done with ASerge's solution, which works as expected.

Just as an aside, in my application I need to programmatically use numbers to find certain parents, as a result of other computations, without user intervention.

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.9.3/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19 ("Tessa"), Windows XP SP3, Windows 7 Professional, Windows 10 Home

 

TinyPortal © 2005-2018