Surely I am overlooking something so obvious and simple here, but I just cannot see it.
I have a treeview, nodes are added to it at runtime and can also be deleted. When I delete a node, there is no longer a selected node in the tree, HideSelection is also set to False but that would make no difference anyway as the selected node is deleted, standard behavior I guess.
Anyway, to reduce the number of times and input required focusing back onto the treeview, I want to automatically reselect a node in the tree after one has been deleted (especially useful if deleting lots of nodes in quick succession as it removes the need to click back onto the treeview).
So lets say I have a tree like this:
This is the behavior pattern I am looking for, using the following scenarios as an example:
Item1
could be selected, when deleted Root
becomes selected.Item2
could be selected, when deleted Item6
becomes selected.Item3
could be selected, when deleted Item4
becomes selected.Item4
could be selected, when deleted Item5
becomes selected.Item5
could be selected, when deleted Item4
becomes selected.Item5
could be selected, when deleted if Item4
is not present, then Item3
should be selected.Item5
could be selected, when deleted if Item3
or Item4
are not present, select Item2
.Item6
could be selected, when deleted Item2
becomes selected.Item7
could be selected, when deleted Item6
becomes selected.I keep getting Index out of bounds and other AV errors (in Lazarus) and that is without even getting to the point of checking where in the tree the current selected node is.
As it stands right now, in my Delete event I have this:
procedure TMainForm.actDeleteExecute(Sender: TObject);
var
SelNode: TTreeNode;
begin
if TreeView1.Selected <> nil then
begin
SelNode := TreeView1.Selected;
TreeView1.Selected.Delete;
TreeView1.SetFocus;
//ShowMessage(SelNode.GetPrev.Text);
TreeView1.Selected.Index := SelNode.Index;
end;
end;
Is this a case of me completely misunderstanding the situation again and making the task needlessly difficult, or is there a lot of work involved to implement such behavior?
Many thanks in advance.
Your mistake is to access the node, to get its index, that you've deleted: SelNode
in your example. It's causing an AV.
Assuming your question is about the Lazarus's TreeView control (as mentioned in the question), you can follow Kobik's suggestion in the comments and find the node to be selected before you delete the item. Or, which I find simpler, you can implement your logic in the OnDeletion
event of the TreeView. This event is fired just before the item is actually destroyed.
procedure TForm1.actDeleteExecute(Sender: TObject);
begin
if Assigned(TreeView1.Selected) then begin
TreeView1.Selected.Delete;
TreeView1.SetFocus;
end;
end;
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
if Assigned(TreeView1.Selected.GetPrevSibling) then
TreeView1.Selected := TreeView1.Selected.GetPrevSibling
else if Assigned(TreeView1.Selected.GetNextSibling) then
TreeView1.Selected := TreeView1.Selected.GetNextSibling
else if Assigned(TreeView1.Selected.GetPrev) then
TreeView1.Selected := TreeView1.Selected.GetPrev
else
TreeView1.Selected := TreeView1.Selected.GetNext; // can be nil
end;
Note that I was unable to follow your logic regarding which item to select when one is deleted, primarily because when a node is deleted all of its children is deleted as well. You can adjust the above to suit your needs.