Difference between revisions of "TTreeView"
m (→Creating a TreeView which loads items only when expansing: Fix title) |
m (→Using Drag and Drop in a TreeView: Fix typo; shorten comments) |
||
(12 intermediate revisions by the same user not shown) | |||
Line 6: | Line 6: | ||
==Adding a new item in code== | ==Adding a new item in code== | ||
+ | |||
To add a sibling node to pre-existing node, use TTreeView.ITems.Add. | To add a sibling node to pre-existing node, use TTreeView.ITems.Add. | ||
− | + | <syntaxhighlight lang=pascal> | |
+ | TreeView1.Items.Add(ATreeNode, 'Added node'); | ||
+ | </syntaxhighlight> | ||
− | To add the first node, it becomes | + | To add the first node, it becomes: |
− | + | <syntaxhighlight lang=pascal> | |
+ | TreeView1.Items.Add(nil, 'First node'); | ||
+ | </syntaxhighlight> | ||
Use TTreeView.Items.AddChild or AddChildObject to add child node. | Use TTreeView.Items.AddChild or AddChildObject to add child node. | ||
− | + | <syntaxhighlight lang=pascal> | |
+ | TreeView1.Items.AddChild(ATreeNode, 'Child node'); | ||
+ | </syntaxhighlight> | ||
==Creating a TreeView which loads items only when expanding== | ==Creating a TreeView which loads items only when expanding== | ||
Line 27: | Line 34: | ||
==A Short example of using TTreeview== | ==A Short example of using TTreeview== | ||
+ | |||
Here is a quick & dirty example - I tested on Windows Lazarus 0.9.26: | Here is a quick & dirty example - I tested on Windows Lazarus 0.9.26: | ||
Line 36: | Line 44: | ||
<syntaxhighlight lang=pascal> | <syntaxhighlight lang=pascal> | ||
+ | ... | ||
+ | |||
+ | Var | ||
+ | Node: TTreeNode; | ||
+ | |||
+ | ... | ||
+ | |||
procedure TForm1.Button1Click(Sender: TObject); | procedure TForm1.Button1Click(Sender: TObject); | ||
var | var | ||
Line 70: | Line 85: | ||
exit; | exit; | ||
− | + | // if selected node has child nodes, first ask for confirmation | |
if treeview1.Selected.HasChildren then | if treeview1.Selected.HasChildren then | ||
− | if messagedlg( 'Delete node and all children ?',mtConfirmation, [mbYes,mbNo],0 ) <> | + | if messagedlg( 'Delete node and all children ?',mtConfirmation, [mbYes,mbNo],0 ) <> mrNo then |
exit; | exit; | ||
DeleteNode(TreeView1.Selected); | DeleteNode(TreeView1.Selected); | ||
Line 81: | Line 96: | ||
Delete will delete the currently selected node. If it doesn't have children, it will delete it immediately, but if it has children, it will first ask. | Delete will delete the currently selected node. If it doesn't have children, it will delete it immediately, but if it has children, it will first ask. | ||
+ | |||
+ | == How to move a node in TTreeview == | ||
+ | |||
+ | Assuming you have UP and Down buttons to move the selected node in the TTreeview, these procedures will achieve moving the selected node. | ||
+ | |||
+ | <syntaxhighlight lang=pascal> | ||
+ | procedure TForm1.UpBtnClick(Sender: TObject); | ||
+ | begin | ||
+ | // Ensure a node is selected | ||
+ | if(Treeview1.Selected <> nil) then | ||
+ | // Ensure there is a previous sibling node | ||
+ | if Treeview1.Selected.GetPrevSibling <> nil then | ||
+ | // If we have made it this far, move it UP | ||
+ | Treeview1.Selected.MoveTo(Treeview1.Selected.GetPrevSibling, naInsert); | ||
+ | end; | ||
+ | |||
+ | procedure TForm1.DownBtnClick(Sender: TObject); | ||
+ | begin | ||
+ | // Ensure a node is selected | ||
+ | if(Treeview1.Selected <> nil) then | ||
+ | // Ensure there is a next sibling node | ||
+ | if Treeview1.Selected.GetNextSibling <> nil then | ||
+ | // If we have made it this far, move it DOWN | ||
+ | Treeview1.Selected.MoveTo(Treeview1.Selected.GetNextSibling, naInsertBehind); | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Note: These procedures will only move nodes which are at the same level in the TTreeview. | ||
+ | |||
+ | {| class="wikitable" | ||
+ | ! colspan=2 | Table of attachment mode of Nodes | ||
+ | |- | ||
+ | ! Mode !! Effect | ||
+ | |- | ||
+ | | naAdd || add as last sibling of target node | ||
+ | |- | ||
+ | | naAddFirst || add as first sibling of target node | ||
+ | |- | ||
+ | | naAddChild || add as last child of target node | ||
+ | |- | ||
+ | | naAddChildFirst || add as first child of target node | ||
+ | |- | ||
+ | | naInsert || insert in front of target node | ||
+ | |- | ||
+ | | naInsertBehind || insert behind target node | ||
+ | |- | ||
+ | |} | ||
==Example of using Multiple Node Selection for Multiple User Selections== | ==Example of using Multiple Node Selection for Multiple User Selections== | ||
Line 113: | Line 175: | ||
== Using Drag and Drop in a TreeView == | == Using Drag and Drop in a TreeView == | ||
If you want to allow a drag and drop function in your treeview, you need to : | If you want to allow a drag and drop function in your treeview, you need to : | ||
+ | |||
# Set to DmAutomatic, the property "Drag Mode" of your treeview | # Set to DmAutomatic, the property "Drag Mode" of your treeview | ||
− | # Create | + | # Create events for <code>onDragDrop</code> and <code>OnDragOver</code>: |
+ | |||
+ | <syntaxhighlight lang=pascal> | ||
+ | ... | ||
+ | |||
+ | Var | ||
+ | Node: TTreeNode; | ||
+ | |||
+ | ... | ||
− | < | + | procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer); |
+ | begin | ||
+ | Treeview1 := TTreeView(Sender); { Sender is TreeView where the data is being dropped } | ||
+ | Node := Treeview1.GetNodeAt(x,y); { x,y are drop coordinates (relative to the Sender) } | ||
+ | { since Sender is TreeView we can evaluate } | ||
+ | { a tree at the X,Y coordinates } | ||
+ | if Source = Sender then { drop is happening within a TreeView } | ||
+ | begin | ||
+ | if Assigned(Treeview1.Selected) and { check if any node has been selected } | ||
+ | (Node <> Treeview1.Selected) then { and we're dropping to another node } | ||
+ | begin | ||
+ | if Node <> nil then | ||
+ | Treeview1.Selected.MoveTo(Node, naAddChild) { complete drop, by moving selected node } | ||
+ | else | ||
+ | Treeview1.Selected.MoveTo(Node, naAdd); { complete drop, by moving selected node in root } | ||
+ | end; | ||
+ | end; | ||
+ | end; | ||
+ | |||
+ | procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); | ||
begin | begin | ||
Accept := true; | Accept := true; | ||
− | end; | + | end; |
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
== Comments on Events == | == Comments on Events == | ||
− | Event | + | |
+ | Event handlers are convenient places for developing LCL applications. There are some peculiar events for TTreeview. | ||
'''When selected node is changed''' | '''When selected node is changed''' | ||
Line 128: | Line 220: | ||
OnChange, OnChanging - These events are called when selected node is shifted from one to another. OnChanging occur before the shift is done, and OnChange after actual shift. The headers of procedures are as follows. To prevent the shift, one may set AllowChange variable of OnChanging event handler to false. | OnChange, OnChanging - These events are called when selected node is shifted from one to another. OnChanging occur before the shift is done, and OnChange after actual shift. The headers of procedures are as follows. To prevent the shift, one may set AllowChange variable of OnChanging event handler to false. | ||
− | + | <syntaxhighlight lang=pascal> | |
− | + | procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode); | |
+ | procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean); | ||
+ | </syntaxhighlight> | ||
− | + | Care must be taken, as the node variable of both procedures points to a "new" node, which is to move to. In Delphi, the node variable of the OnChanging event handler points to the node that selection is about to leave. | |
'''When a node is inserted''' | '''When a node is inserted''' | ||
− | When a new node is inserted, related events occur in following order. | + | When a new node is inserted, related events occur in the following order. |
1) OnNodeChanged | 1) OnNodeChanged | ||
Line 144: | Line 238: | ||
'''When deleting a node''' | '''When deleting a node''' | ||
− | When the selected node is deleted, following events occur. | + | When the selected node is deleted, the following events occur. |
1) OnDelete | 1) OnDelete | ||
Line 151: | Line 245: | ||
4) OnChange : This is called because when you delete a node, another node is selected. | 4) OnChange : This is called because when you delete a node, another node is selected. | ||
− | If unselected node is deleted, e.g. | + | If an unselected node is deleted, e.g. programmatically, then only the OnDelete event handler is called. |
'''When Form is Closed''' | '''When Form is Closed''' | ||
− | OnChanging event occurs, as the selected node is "de"selected. But OnChanging eventhander is executed AFTER the form is closed. This means that you cannot access the form's other data (other controls, other variables, etc.) within OnChanging event handler procedure. | + | OnChanging event occurs, as the selected node is "de"selected. But OnChanging eventhander is executed AFTER the form is closed. This means that you cannot access the form's other data (other controls, other variables, etc.) within the OnChanging event handler procedure. |
'''When Drag&Drop is done''' | '''When Drag&Drop is done''' | ||
− | When you drag a node to another node and drop, following events occur. | + | When you drag a node to another node and drop, the following events occur. |
1) OnSelectionChanged | 1) OnSelectionChanged | ||
Line 166: | Line 260: | ||
==See also == | ==See also == | ||
+ | * [[Drag and Drop sample]] | ||
* [[doc:/lcl/comctrls/ttreeview.html| TTreeView doc]] | * [[doc:/lcl/comctrls/ttreeview.html| TTreeView doc]] | ||
* [[TListView]] | * [[TListView]] |
Revision as of 13:12, 10 April 2021
│
English (en) │
español (es) │
suomi (fi) │
français (fr) │
magyar (hu) │
русский (ru) │
A TTreeView is a graphical control element that presents a hierarchical view of information. Each item can have a number of subitems.
An item can be expanded to reveal subitems, if any exist, and collapsed to hide subitems.
Adding a new item in code
To add a sibling node to pre-existing node, use TTreeView.ITems.Add.
TreeView1.Items.Add(ATreeNode, 'Added node');
To add the first node, it becomes:
TreeView1.Items.Add(nil, 'First node');
Use TTreeView.Items.AddChild or AddChildObject to add child node.
TreeView1.Items.AddChild(ATreeNode, 'Child node');
Creating a TreeView which loads items only when expanding
To add the expansion symbol to a node without subitems use:
MyNode.HasChildren := True;
And then set an event handler for the OnExpanding event. In this even you should return if the expansion can actually be made or not and when yes, you should add subitems to the node. If the expansion cannot be done, the expansion symbol will be automatically removed even if you have previously set HasChildren to true.
A Short example of using TTreeview
Here is a quick & dirty example - I tested on Windows Lazarus 0.9.26:
Create a new application. On Form1 add an empty treeview, a button1 with caption "Add Child" and a button2 with caption "Delete"
For the buttons' OnClick events, assign the following code, compile & run.
Code:
...
Var
Node: TTreeNode;
...
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
s: string;
begin
// if there are no nodes, create a root node with a parent of nil
if TreeView1.Items.Count = 0 then
begin
Treeview1.Items.Add (nil,'Root Node');
exit;
end;
// Set up a simple text for each new node - Node1 , Node2 etc
i := treeview1.Items.Count;
s := 'Node ' + inttostr(i);
//Add a new node to the currently selected node
if TreeView1.Selected <> nil then
Treeview1.Items.AddChild(Treeview1.Selected ,s);
end;
procedure TForm1.Button2Click(Sender: TObject);
//A procedure to recursively delete nodes
procedure DeleteNode(Node:TTreeNode);
begin
while Node.HasChildren do
DeleteNode(node.GetLastChild);
TreeView1.Items.Delete(Node) ;
end;
begin
if TreeView1.Selected = nil then
exit;
// if selected node has child nodes, first ask for confirmation
if treeview1.Selected.HasChildren then
if messagedlg( 'Delete node and all children ?',mtConfirmation, [mbYes,mbNo],0 ) <> mrNo then
exit;
DeleteNode(TreeView1.Selected);
end;
When running, the treeview is empty. If you click "Add Child", a root node is created. After that a child will be added to any selected node by clicking "Add Child"
Delete will delete the currently selected node. If it doesn't have children, it will delete it immediately, but if it has children, it will first ask.
How to move a node in TTreeview
Assuming you have UP and Down buttons to move the selected node in the TTreeview, these procedures will achieve moving the selected node.
procedure TForm1.UpBtnClick(Sender: TObject);
begin
// Ensure a node is selected
if(Treeview1.Selected <> nil) then
// Ensure there is a previous sibling node
if Treeview1.Selected.GetPrevSibling <> nil then
// If we have made it this far, move it UP
Treeview1.Selected.MoveTo(Treeview1.Selected.GetPrevSibling, naInsert);
end;
procedure TForm1.DownBtnClick(Sender: TObject);
begin
// Ensure a node is selected
if(Treeview1.Selected <> nil) then
// Ensure there is a next sibling node
if Treeview1.Selected.GetNextSibling <> nil then
// If we have made it this far, move it DOWN
Treeview1.Selected.MoveTo(Treeview1.Selected.GetNextSibling, naInsertBehind);
end;
Note: These procedures will only move nodes which are at the same level in the TTreeview.
Table of attachment mode of Nodes | |
---|---|
Mode | Effect |
naAdd | add as last sibling of target node |
naAddFirst | add as first sibling of target node |
naAddChild | add as last child of target node |
naAddChildFirst | add as first child of target node |
naInsert | insert in front of target node |
naInsertBehind | insert behind target node |
Example of using Multiple Node Selection for Multiple User Selections
If you select your TTreeview component, go to the object inspector and in the options sections set 'tvoAllowMultiSelect' to true. Then, to iterate over the selected nodes and obtain the paths of the chosen folders or files, the following example will populate the text paths of those selected nodes to a memo field :
Code:
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
if TreeView1.SelectionCount=0 then
exit;
Memo1.Lines.Clear;
for i:=0 to TreeView1.SelectionCount-1 do
Memo1.Lines.Add(TreeView1.Selections[i].GetTextPath);
end;
Freeing TreeNode Data
Use the TreeView's OnDeletion event to free your object.
procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
TMyObject(Node.Data).Free;
Node.Data := nil;
end;
Using Drag and Drop in a TreeView
If you want to allow a drag and drop function in your treeview, you need to :
- Set to DmAutomatic, the property "Drag Mode" of your treeview
- Create events for
onDragDrop
andOnDragOver
:
...
Var
Node: TTreeNode;
...
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
Treeview1 := TTreeView(Sender); { Sender is TreeView where the data is being dropped }
Node := Treeview1.GetNodeAt(x,y); { x,y are drop coordinates (relative to the Sender) }
{ since Sender is TreeView we can evaluate }
{ a tree at the X,Y coordinates }
if Source = Sender then { drop is happening within a TreeView }
begin
if Assigned(Treeview1.Selected) and { check if any node has been selected }
(Node <> Treeview1.Selected) then { and we're dropping to another node }
begin
if Node <> nil then
Treeview1.Selected.MoveTo(Node, naAddChild) { complete drop, by moving selected node }
else
Treeview1.Selected.MoveTo(Node, naAdd); { complete drop, by moving selected node in root }
end;
end;
end;
procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
Accept := true;
end;
Comments on Events
Event handlers are convenient places for developing LCL applications. There are some peculiar events for TTreeview.
When selected node is changed
OnChange, OnChanging - These events are called when selected node is shifted from one to another. OnChanging occur before the shift is done, and OnChange after actual shift. The headers of procedures are as follows. To prevent the shift, one may set AllowChange variable of OnChanging event handler to false.
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean);
Care must be taken, as the node variable of both procedures points to a "new" node, which is to move to. In Delphi, the node variable of the OnChanging event handler points to the node that selection is about to leave.
When a node is inserted
When a new node is inserted, related events occur in the following order.
1) OnNodeChanged 2) (OnChanging): This is called if there was a previously selected node. 3) OnSelectionChanged 4) OnChange
When deleting a node
When the selected node is deleted, the following events occur.
1) OnDelete 2) OnChanging 3) SelectionChanged 4) OnChange : This is called because when you delete a node, another node is selected.
If an unselected node is deleted, e.g. programmatically, then only the OnDelete event handler is called.
When Form is Closed
OnChanging event occurs, as the selected node is "de"selected. But OnChanging eventhander is executed AFTER the form is closed. This means that you cannot access the form's other data (other controls, other variables, etc.) within the OnChanging event handler procedure.
When Drag&Drop is done
When you drag a node to another node and drop, the following events occur.
1) OnSelectionChanged 2) OnNodeChanged 3) OnChange
See also