8
8
from compas .datastructures import Tree
9
9
from compas .datastructures import TreeNode
10
10
11
+ from .component import Component
11
12
12
- class Treeform (QTreeWidget ):
13
+
14
+ class Treeform (Component ):
13
15
"""
14
- Class for displaying tree-like data.
15
- Treeform is an abstract class that could be placed in either the viewport or the sidedock.
16
+ A component for displaying hierarchical tree-like data in a tree widget.
17
+
18
+ This component provides a flexible way to visualize tree structures with
19
+ customizable columns and background colors. It supports selection callbacks
20
+ and can be used in various UI layouts.
16
21
17
22
Parameters
18
23
----------
19
- tree : :class:`compas.datastructures.Tree`
20
- The tree to be displayed. An typical example is the scene
21
- object tree: :attr:`compas_viewer.viewer.Viewer._tree`.
22
- columns : dict[str, callable]
23
- A dictionary of column names and their corresponding attributes.
24
- Example: ``{"Name": (lambda o: o.name), "Object": (lambda o: o)}``
24
+ tree : Tree, optional
25
+ The tree data structure to display. Defaults to an empty tree.
26
+ columns : dict[str, Callable], optional
27
+ Dictionary mapping column names to functions that extract values from tree nodes.
28
+ Defaults to {"Name": lambda node: node.name, "Value": lambda node: node.attributes.get("value", "")}.
25
29
show_headers : bool, optional
26
- Show the header of the tree.
27
- Defaults to ``True``.
30
+ Whether to show column headers. Defaults to True.
28
31
stretch : int, optional
29
- Stretch factor of the tree in the grid layout .
30
- Defaults to ``2``.
31
- backgrounds : dict[str, callable], optional
32
- A dictionary of column names and their corresponding color.
33
- Example: ``{"Object-Color": (lambda o: o.surfacecolor)}``
32
+ Stretch factor for the tree widget in grid layouts. Defaults to 2 .
33
+ backgrounds : dict[str, Callable], optional
34
+ Dictionary mapping column names to functions that return background colors.
35
+ action : Callable, optional
36
+ Function to call when tree items are selected. Receives the selected node as argument.
34
37
35
38
Attributes
36
39
----------
37
- tree : :class:`compas.datastructures.Tree`
38
- The tree to be displayed.
39
-
40
- See Also
41
- --------
42
- :class:`compas.datastructures.Tree`
43
- :class:`compas.datastructures.tree.TreeNode`
44
- :class:`compas_viewer.layout.SidedockLayout`
45
-
46
- References
47
- ----------
48
- :PySide6:`PySide6/QtWidgets/QTreeWidget`
40
+ widget : QTreeWidget
41
+ The Qt tree widget for displaying the data.
42
+ tree : Tree
43
+ The tree data structure being displayed.
44
+ columns : dict[str, Callable]
45
+ Column definitions for the tree display.
46
+ stretch : int
47
+ Stretch factor for layout purposes.
48
+ action : Callable or None
49
+ Selection action function.
49
50
50
51
Examples
51
52
--------
52
- .. code-block:: python
53
-
54
- from compas_viewer import Viewer
55
-
56
- viewer = Viewer()
57
-
58
- for i in range(10):
59
- for j in range(10):
60
- sp = viewer.scene.add(Sphere(0.1, Frame([i, j, 0], [1, 0, 0], [0, 1, 0])), name=f"Sphere_{i}_{j}")
61
-
62
- viewer.layout.sidedock.add_element(Treeform(viewer._tree, {"Name": (lambda o: o.object.name), "Object": (lambda o: o.object)}))
63
-
64
- viewer.show()
65
-
53
+ >>> # Create a simple tree form
54
+ >>> treeform = Treeform()
55
+ >>> treeform.update()
56
+
57
+ >>> # Create with custom columns
58
+ >>> columns = {"Name": lambda node: node.name, "Type": lambda node: type(node).__name__}
59
+ >>> treeform = Treeform(columns=columns)
60
+
61
+ >>> # Create with selection action
62
+ >>> def on_select(node):
63
+ ... print(f"Selected: {node.name}")
64
+ >>> treeform = Treeform(action=on_select)
66
65
"""
67
66
68
67
def __init__ (
@@ -72,30 +71,38 @@ def __init__(
72
71
show_headers : bool = True ,
73
72
stretch : int = 2 ,
74
73
backgrounds : Optional [dict [str , Callable ]] = None ,
75
- callback : Optional [Callable ] = None ,
74
+ action : Optional [Callable ] = None ,
76
75
):
77
76
super ().__init__ ()
77
+ self .widget = QTreeWidget ()
78
+
78
79
self .columns = columns or {"Name" : lambda node : node .name , "Value" : lambda node : node .attributes .get ("value" , "" )}
79
- self .setColumnCount (len (self .columns ))
80
- self .setHeaderLabels (list (self .columns .keys ()))
81
- self .setHeaderHidden (not show_headers )
80
+ self .widget . setColumnCount (len (self .columns ))
81
+ self .widget . setHeaderLabels (list (self .columns .keys ()))
82
+ self .widget . setHeaderHidden (not show_headers )
82
83
self .stretch = stretch
83
84
self ._backgrounds = backgrounds
84
85
85
86
self .tree = tree or Tree ()
86
- self .callback = callback
87
- self .itemSelectionChanged .connect (self .on_item_selection_changed )
87
+ self .action = action
88
+ self .widget . itemSelectionChanged .connect (self .on_item_selection_changed )
88
89
89
90
def update (self ):
90
- self .clear ()
91
+ """Update the tree widget display with the current tree data.
92
+
93
+ This method clears the existing tree widget items and rebuilds the display
94
+ based on the current tree structure, applying column mappings and background
95
+ colors as configured.
96
+ """
97
+ self .widget .clear ()
91
98
for node in self .tree .traverse ("breadthfirst" ):
92
99
if node .is_root :
93
100
continue
94
101
95
102
strings = [str (c (node )) for _ , c in self .columns .items ()]
96
103
97
104
if node .parent .is_root : # type: ignore
98
- node .attributes ["widget_item" ] = QTreeWidgetItem (self , strings ) # type: ignore
105
+ node .attributes ["widget_item" ] = QTreeWidgetItem (self . widget , strings ) # type: ignore
99
106
else :
100
107
node .attributes ["widget_item" ] = QTreeWidgetItem (
101
108
node .parent .attributes ["widget_item" ],
@@ -109,6 +116,18 @@ def update(self):
109
116
node .attributes ["widget_item" ].setBackground (list (self .columns .keys ()).index (col ), QColor (* background (node ).rgb255 ))
110
117
111
118
def tree_from_dict (self , data ):
119
+ """Create a tree structure from a dictionary.
120
+
121
+ Parameters
122
+ ----------
123
+ data : dict
124
+ Dictionary containing the hierarchical data to convert to a tree.
125
+
126
+ Returns
127
+ -------
128
+ Tree
129
+ A new Tree object representing the dictionary structure.
130
+ """
112
131
tree = Tree ()
113
132
root = TreeNode ("Root" )
114
133
tree .add (root )
@@ -133,10 +152,25 @@ def add_children(key, data, parent):
133
152
return tree
134
153
135
154
def update_from_dict (self , data ):
155
+ """Update the tree display from a dictionary structure.
156
+
157
+ This is a convenience method that converts dictionary data to a tree
158
+ and updates the display in one step.
159
+
160
+ Parameters
161
+ ----------
162
+ data : dict
163
+ Dictionary containing the hierarchical data to display.
164
+ """
136
165
self .tree = self .tree_from_dict (data )
137
166
self .update ()
138
167
139
168
def on_item_selection_changed (self ):
140
- for item in self .selectedItems ():
141
- if self .callback :
142
- self .callback (item .node )
169
+ """Handle tree item selection changes.
170
+
171
+ This method is called when the selection in the tree widget changes.
172
+ It calls the action function (if provided) with the selected node as argument.
173
+ """
174
+ for item in self .widget .selectedItems ():
175
+ if self .action :
176
+ self .action (item .node )
0 commit comments