Recent

Author Topic: [SOLVED] Delete child node from treeview with pointers to record data.  (Read 587 times)

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Hi,

If I add a node to a treeview, it gets a pointer to a record with data. (My first steps with pointers). When I click on the node I can request the data of the record and when I close I clean up the pointers with:

Code: Pascal  [Select][+][-]
  1. for i := 0 to TreeViewApi.Items.Count-1 do
  2.     get started
  3.       Dispose(PtrFolder(TreeViewApi.Items[i].Data)); // dispose pointer data
  4.     end;

That works fine.
But here's the thing, if I delete a tree node with child nodes I get a memory leak because the pointers of the deleted child nodes and parent nodes still exist.

I thought I'd loop through the children, but I immediately get an index out of bounds message at the first child node.
How can i delete pointers from a deleted childnode with childs?

Code: Pascal  [Select][+][-]
  1. procedure TFrm_Maintain_Api_Data.TreeNodesDeletePointers(Node: TTreeNode);
  2. get started
  3.   Node := Node.GetFirstChild;
  4.   if Node = nil then Exit;
  5.   try
  6.     repeat
  7.       Dispose(PtrFolder(Node[Node.AbsoluteIndex].Data)); // TreeViewApi.Items[i].Data))
  8.  
  9.       TreeNodesDeletePointers(Node);
  10.       Node := Node.GetNextSibling;
  11.     until Node = nil;
  12.   finally
  13.     //
  14.   end;
  15. end;
« Last Edit: November 30, 2022, 08:26:33 pm by Hansvb »

jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #1 on: November 26, 2022, 07:20:06 pm »
use the OnDeletion event to clean up the node?

It hands you the current node being deleted.

The only true wisdom is knowing you know nothing

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Re: Delete child node from treeview with pointers to record data.
« Reply #2 on: November 26, 2022, 07:26:11 pm »

jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #3 on: November 26, 2022, 08:06:01 pm »
I am getting old I guess.(Slow) >:(

I am not as good as I once was, but I am as good once as I was! :D
The only true wisdom is knowing you know nothing

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Re: Delete child node from treeview with pointers to record data.
« Reply #4 on: November 27, 2022, 10:42:17 am »
Hi Jamie,

You're not getting old, I hadn't posted it yet. I wanted to try it first today before posting. I couldn't do it with the OnDeletion event and now I did it differently.

When I right-click on the Treeview, a popup menu opens with the option to delete. When I click delete, the following happens:

Code: Pascal  [Select][+][-]
  1. procedure TFrm_Maintain_Api_Data.MenuItemDeleteClick(Sender: TObject);
  2. begin
  3.   // check if delete is allowed and then...
  4.           DeleteNode(TreeViewApi.Selected); // delete the node and the pointer data
  5. end;
  6.  
  7. procedure TFrm_Maintain_Api_Data.DeleteNode(Node: TTreeNode);
  8. begin
  9.   while Node.HasChildren do
  10.     begin
  11.       Dispose(PtrFolder(TreeViewApi.Items[node.GetLastChild.Index].Data));
  12.       DeleteNode(node.GetLastChild);
  13.     end;
  14.   TreeViewApi.Items.Delete(Node);
  15. end;

It look like this removes also Data from other node and then the form close goes wrong.


Code: Pascal  [Select][+][-]
  1. procedure TFrm_Maintain_Api_Data.FormClose(Sender: TObject;
  2.   var CloseAction: TCloseAction);
  3. var
  4.   i : Integer;
  5. begin
  6.   if assigned(MaintainFolders) then
  7.   MaintainFolders.Free;
  8.  
  9.   for i := 0 to TreeViewApi.Items.Count-1 do
  10.     begin
  11.       if PtrFolder(TreeViewApi.Items[i].Data) <> nil then
  12.         Dispose(PtrFolder(TreeViewApi.Items[i].Data)); //<--Error
  13.     end;
  14.  
  15.   SaveSettings();
  16. end;
« Last Edit: November 27, 2022, 10:46:54 am by Hansvb »

Zath

  • Sr. Member
  • ****
  • Posts: 385
Re: Delete child node from treeview with pointers to record data.
« Reply #5 on: November 27, 2022, 11:07:53 am »
Althought Delphi orientated, you might find some videos by Huw Collinbourne useful for your project.
He has made several short videos about the Treeview component as part of his own project.

https://youtu.be/DxxvStPF9gM

If I'm not allowed to post the YT link, search for "Program the TreeView in Delphi".



jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #6 on: November 27, 2022, 11:36:00 am »
Somehow something does not look correct.

Firstly, when deleting a data record elsewhere you should set the pointer field in the node to Nil, so that further processing can ignore it.

 Also, I was always under the impression that if you delete a parent all other nodes that follow that parent also gets deleted, hence the reason for using the OnDeletion event, which passes each node to you so you can inspect it, process it, etc...
 
 I'll have to perform some scientific experiments here.

 :D
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #7 on: November 27, 2022, 11:59:06 am »
Ok, Test done.

Yes, I was correct with that assumption.!

 if you delete a parent node, all child, and their children get deleted as well.

 so this means you only need to delete one node, the others will delete automatically.
 
 You need to implement the OnDeletion event so that you can clean up each node as the TreeView control is deleting them.

  Don't cycle through the child controls yourself to do this.

 I put in a root node and 2 children's nodes and then deleted just the root node.

 Results was all child nodes got deleted and each one was passed to the OnDeletion event before removal from the list.

 so simply do your record data clean up at the OnDeletion
The only true wisdom is knowing you know nothing

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Re: Delete child node from treeview with pointers to record data.
« Reply #8 on: November 28, 2022, 12:58:10 pm »
Hi,

Clearing the treeview Data view may not be the problem but closing the main screen. See attached working example. Line 123 in Main_Form.pas does the trick. (Line 15 in the example below). I do not like it because i do not know why i have to disable an event handler when i free an object.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  2. var
  3.   i,j : Integer;
  4. begin
  5.  j :=   TreeView1.Items.Count;
  6.  
  7.   for i := 0 to TreeView1.Items.Count-1 do
  8.     begin
  9.       if PtrFolder(TreeView1.Items[i].Data) <> nil then
  10.         Dispose(PtrFolder(TreeView1.Items[i].Data)); // dispose pointer data
  11.     end;
  12.  
  13.   if Assigned(MaintainFolders) then
  14.     begin
  15.       TreeView1.OnDeletion:=nil;   // This did it <<===========
  16.       MaintainFolders.Free;
  17.     end;
  18. end;  

jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #9 on: November 28, 2022, 01:46:08 pm »
Unless there is something wrong with the TreeView that is forcing you to do it this way, which I don't see, I really think you are not understanding the process.

If you flat out call the Free on the TreeView, It will send all of the nodes to the OnDeletion event for you to do any processing on them.

 So, in your FormClose simply do this,

 MyTreeView.Free;

 and you're done.

 what happens is the control will send each node to the OnDeletion event and that is where you then test for a non-nil pointer in the object and delete your record.

 The final FREE process does not end until all nodes have been sent to the OnDeletion event. So this means you still can reference other items in the Control while this is taking place.

 Granted that maybe the TtreeView should have a property to be tested indicating if the control is in the process of being unloaded so that you could tester more but That is something that can be done if needed. For example, you could use the TAG property to be set to a known value before you call the FREE, so that when the OnDeletion event is being called you can reference the TAG of the control to test for this condition.

 Have a good day, whatever works for you at this point, I guess.


The only true wisdom is knowing you know nothing

bytebites

  • Hero Member
  • *****
  • Posts: 534
Re: Delete child node from treeview with pointers to record data.
« Reply #10 on: November 28, 2022, 01:52:32 pm »
There is not MyTreeView
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  2. begin  
  3.       MaintainFolders.Free;
  4. end;
  5.  

jamie

  • Hero Member
  • *****
  • Posts: 5045
Re: Delete child node from treeview with pointers to record data.
« Reply #11 on: November 28, 2022, 02:05:29 pm »
There is not MyTreeView
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  2. begin  
  3.       MaintainFolders.Free;
  4. end;
  5.  

Another country heard from. Do we have comedians here?

The only true wisdom is knowing you know nothing

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Re: Delete child node from treeview with pointers to record data.
« Reply #12 on: November 28, 2022, 07:22:35 pm »
Quote
I really think you are not understanding the process.
Very true.

But i learn by doing and often I have to see things before I understand them. I could only find examples that add data to a Node but nowhere a good example how to remove it from some Nodes.

Thanks, you got me searching. I think I'm a lot further than yesterday.
 :)

egsuh

  • Hero Member
  • *****
  • Posts: 1064
Re: Delete child node from treeview with pointers to record data.
« Reply #13 on: November 29, 2022, 06:36:17 am »
I have changed some of  your codes of mainform. This works fine, and no memory leaks as far as I have checked. Cheers!

Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$R *.lfm}
  4.  
  5. { TForm1 }
  6.  
  7. procedure TForm1.MenuItem1Click(Sender: TObject);  // Add Node
  8. var
  9.   Node : TTreeNode;
  10.   NewFolder : PtrFolder;
  11. begin
  12.   Node := TreeView1.Selected;
  13.  
  14.   if Node <> nil
  15.      then MaintainFolders.FolderParentGuid := PtrFolder(Node.Data)^.FolderGuid
  16.      else MaintainFolders.FolderParentGuid := '';
  17.   NewFolder := MaintainFolders.PrepareNewFolder('New Folder');
  18.   Node := TreeView1.Items.AddChildObject(Node, 'New Folder', NewFolder);
  19. end;
  20.  
  21. procedure TForm1.MenuItem2Click(Sender: TObject); // Delete Node
  22. var
  23.    i : Integer;
  24.    Node: TTreeNode;
  25. begin
  26.    Node := Treeview1.Selected;
  27.    if Node <> nil then Node.Delete;
  28. end;
  29.  
  30. procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
  31. begin
  32.    Edit6.Text:= IntToStr(TreeView1.Items.Count);
  33. end;
  34.  
  35. procedure TForm1.TreeView1Click(Sender: TObject);
  36. var
  37.    p : PtrFolder;
  38.    Node: TTreeNode;
  39. begin
  40.    Node := TreeView1.Selected;
  41.    if Node <> nil then p := Node.Data else p := nil;
  42.    if p <> nil then begin
  43.       Edit1.Text := p^.FolderType;
  44.       Edit2.Text := p^.ParentFolder;
  45.       Edit3.Text := P^.FolderGuid;
  46.  
  47.       Edit4.Text := IntToStr(Node.Index);
  48.       Edit5.Text := IntToStr(Node.AbsoluteIndex);
  49.    end
  50.    else begin
  51.      Edit1.Text := '';
  52.      Edit2.Text := '';
  53.      Edit3.Text := '';
  54.  
  55.      Edit4.Text := '';
  56.      Edit5.Text := '';
  57.    end;
  58. end;
  59.  
  60. procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
  61. var
  62.    p: ptrFolder;
  63. begin
  64.   if (Node.Data <> nil) { and (Node.Text <> 'RootNode') } then
  65.     begin
  66.        p := Node.Data;
  67.        Dispose(p);
  68.     end;
  69. end;
  70.  
  71. procedure TForm1.FormCreate(Sender: TObject);
  72. begin
  73.    MaintainFolders := TFolder.Create;
  74.    AddRootNode;
  75. end;
  76.  
  77. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  78. begin
  79.    TreeView1.Items.Clear;
  80.    MaintainFolders.Free;
  81. end;
  82.  
  83. procedure TForm1.AddRootNode;
  84. var
  85.   NewFolder : PtrFolder;
  86.   FolderName : String;
  87. begin
  88.   FolderName := 'RootNode';
  89.   MaintainFolders.FolderParentGuid := '';
  90.   NewFolder := MaintainFolders.PrepareNewFolder(FolderName);
  91.   Treeview1.Items.AddChildObject(nil, FolderName, NewFolder);
  92. end;
  93.  
  94. end.

Hansvb

  • Sr. Member
  • ****
  • Posts: 453
Re: [SOLVED] Delete child node from treeview with pointers to record data.
« Reply #14 on: November 30, 2022, 08:28:55 pm »
Thanks.
My 'solution' was way too difficult. I think i begin to understand it now. It's easier than I thought.

 

TinyPortal © 2005-2018