Skip to content

Commit 811d77f

Browse files
Fix for setting selected and expanded state of QTreeWidgetItems (#139)
* Fix for setting selected and expanded state of QTreeWidgetItems The parent property is often empty because Collagraph initializes objects without any knowledge about the tree / parents, and the parent property is read-only and apparently not updated when a QTreeWidgetItem is inserted into the hierarchy. The treeWidget property is a better indicator of the mounted state of an item. * Add tests and example for selection and expanded state of treewidgetitems
1 parent c7f8988 commit 811d77f

3 files changed

Lines changed: 429 additions & 3 deletions

File tree

collagraph/renderers/pyside/objects/treewidgetitem.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def insert(self, el: QTreeWidgetItem, anchor=None):
1111

1212
if anchor is not None:
1313
index = self.indexOfChild(anchor)
14-
if el.parent():
14+
if self.treeWidget():
1515
self.removeChild(el)
1616
self.insertChild(index, el)
1717
else:
@@ -46,12 +46,12 @@ def set_attribute(self, attr, value):
4646
for col, data in value.items():
4747
self.setText(col, data)
4848
case "expanded":
49-
if not self.parent():
49+
if not tree_widget:
5050
self._expanded = value
5151
else:
5252
self.setExpanded(value)
5353
case "selected":
54-
if not self.parent():
54+
if not tree_widget:
5555
self._selected = value
5656
else:
5757
self.setSelected(value)
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
<!--
2+
Run this example as follows:
3+
uv run collagraph examples/pyside/treewidget_selection_demo.cgx
4+
5+
This example demonstrates reactive selection and expanded states
6+
on QTreeWidgetItems. Click the buttons to toggle selection and
7+
expanded states of individual items.
8+
-->
9+
<window title="Tree Widget Selection Demo" :size="[600, 500]">
10+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
11+
<label text="Tree Widget Selection and Expanded State Demo" />
12+
<label text="Use the buttons below to toggle selection and expanded states" />
13+
14+
<widget :layout="{'type': 'Box', 'direction': 'LeftToRight'}">
15+
<!-- Tree widget -->
16+
<treewidget
17+
:column-count="1"
18+
:header-labels="['Item']"
19+
>
20+
<treewidgetitem
21+
:selected="item1_selected"
22+
:expanded="item1_expanded"
23+
:content="{0: 'Parent Item 1'}"
24+
>
25+
<treewidgetitem :content="{0: 'Child 1.1'}">
26+
</treewidgetitem>
27+
<treewidgetitem :content="{0: 'Child 1.2'}">
28+
</treewidgetitem>
29+
</treewidgetitem>
30+
31+
<treewidgetitem
32+
:selected="item2_selected"
33+
:expanded="item2_expanded"
34+
:content="{0: 'Parent Item 2'}"
35+
>
36+
<treewidgetitem :content="{0: 'Child 2.1'}">
37+
</treewidgetitem>
38+
<treewidgetitem :content="{0: 'Child 2.2'}">
39+
</treewidgetitem>
40+
<treewidgetitem :content="{0: 'Child 2.3'}">
41+
</treewidgetitem>
42+
</treewidgetitem>
43+
44+
<treewidgetitem
45+
:selected="item3_selected"
46+
:expanded="item3_expanded"
47+
:content="{0: 'Parent Item 3'}"
48+
>
49+
<treewidgetitem :content="{0: 'Child 3.1'}">
50+
</treewidgetitem>
51+
</treewidgetitem>
52+
</treewidget>
53+
54+
<!-- Control panel -->
55+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
56+
<groupbox title="Item 1 Controls">
57+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
58+
<button
59+
:text="'Selected: ' + str(item1_selected)"
60+
@clicked="toggle_item1_selected"
61+
/>
62+
<button
63+
:text="'Expanded: ' + str(item1_expanded)"
64+
@clicked="toggle_item1_expanded"
65+
/>
66+
</widget>
67+
</groupbox>
68+
69+
<groupbox title="Item 2 Controls">
70+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
71+
<button
72+
:text="'Selected: ' + str(item2_selected)"
73+
@clicked="toggle_item2_selected"
74+
/>
75+
<button
76+
:text="'Expanded: ' + str(item2_expanded)"
77+
@clicked="toggle_item2_expanded"
78+
/>
79+
</widget>
80+
</groupbox>
81+
82+
<groupbox title="Item 3 Controls">
83+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
84+
<button
85+
:text="'Selected: ' + str(item3_selected)"
86+
@clicked="toggle_item3_selected"
87+
/>
88+
<button
89+
:text="'Expanded: ' + str(item3_expanded)"
90+
@clicked="toggle_item3_expanded"
91+
/>
92+
</widget>
93+
</groupbox>
94+
95+
<groupbox title="Bulk Actions">
96+
<widget :layout="{'type': 'Box', 'direction': 'TopToBottom'}">
97+
<button
98+
text="Select All"
99+
@clicked="select_all"
100+
/>
101+
<button
102+
text="Deselect All"
103+
@clicked="deselect_all"
104+
/>
105+
<button
106+
text="Expand All"
107+
@clicked="expand_all"
108+
/>
109+
<button
110+
text="Collapse All"
111+
@clicked="collapse_all"
112+
/>
113+
</widget>
114+
</groupbox>
115+
</widget>
116+
</widget>
117+
118+
<label :text="status_text()" />
119+
</widget>
120+
</window>
121+
122+
<script>
123+
import collagraph as cg
124+
125+
126+
class TreeWidgetSelectionDemo(cg.Component):
127+
def init(self):
128+
self.state["item1_selected"] = True
129+
self.state["item1_expanded"] = True
130+
self.state["item2_selected"] = False
131+
self.state["item2_expanded"] = True
132+
self.state["item3_selected"] = False
133+
self.state["item3_expanded"] = False
134+
135+
def toggle_item1_selected(self):
136+
self.state["item1_selected"] = not self.state["item1_selected"]
137+
138+
def toggle_item1_expanded(self):
139+
self.state["item1_expanded"] = not self.state["item1_expanded"]
140+
141+
def toggle_item2_selected(self):
142+
self.state["item2_selected"] = not self.state["item2_selected"]
143+
144+
def toggle_item2_expanded(self):
145+
self.state["item2_expanded"] = not self.state["item2_expanded"]
146+
147+
def toggle_item3_selected(self):
148+
self.state["item3_selected"] = not self.state["item3_selected"]
149+
150+
def toggle_item3_expanded(self):
151+
self.state["item3_expanded"] = not self.state["item3_expanded"]
152+
153+
def select_all(self):
154+
self.state["item1_selected"] = True
155+
self.state["item2_selected"] = True
156+
self.state["item3_selected"] = True
157+
158+
def deselect_all(self):
159+
self.state["item1_selected"] = False
160+
self.state["item2_selected"] = False
161+
self.state["item3_selected"] = False
162+
163+
def expand_all(self):
164+
self.state["item1_expanded"] = True
165+
self.state["item2_expanded"] = True
166+
self.state["item3_expanded"] = True
167+
168+
def collapse_all(self):
169+
self.state["item1_expanded"] = False
170+
self.state["item2_expanded"] = False
171+
self.state["item3_expanded"] = False
172+
173+
def status_text(self):
174+
selected_count = sum([
175+
int(self.state["item1_selected"]),
176+
int(self.state["item2_selected"]),
177+
int(self.state["item3_selected"]),
178+
])
179+
expanded_count = sum([
180+
int(self.state["item1_expanded"]),
181+
int(self.state["item2_expanded"]),
182+
int(self.state["item3_expanded"]),
183+
])
184+
return f"Status: {selected_count} items selected, {expanded_count} items expanded"
185+
</script>

0 commit comments

Comments
 (0)