Issue
have a PySide6 QTreeWidget with some Elements and Checkboxes, very simple. What i cannot getting to work is how can i make s Single Selection with the Checkboxes? What works is SingleSelection without the Checkboxes, but not when i only use the Checkboxes itself. I wann use only Checkboxes and not Mouseclicks on the row, i did that with
tv.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
tv.setFocusPolicy(QtCore.Qt.NoFocus)
My Idea was set a itemChanged handler function for it and when a checkbox is clicked i run through all items, set all item checkboxes to uncheck with
child.setCheckState(0, QtCore.Qt.Unchecked)
and after that set the item that is selected from the handler to checked.
def handle_statechange(item):
selected_item = item.text(0)
for i in range(tv.invisibleRootItem().childCount()):
child = tv.invisibleRootItem().child(i)
child.setCheckState(0, QtCore.Qt.Unchecked)
item.setCheckState(0, QtCore.Qt.Checked)
But that doesnt work. How can i make this behavior? Thanks!
Here is small sample Code
import sys
from PySide6 import QtGui, QtCore, QtWidgets
testdict = {'TEST1': 'Testname1',
'TEST2': 'Testname2',
'TEST3': 'Testname3',
'TEST4': 'Testname4',
}
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
widget.setWindowTitle("test")
widget.grid = QtWidgets.QGridLayout(widget)
widget.grid.setContentsMargins(5, 5, 5, 5)
widget.hide()
tv = QtWidgets.QTreeWidget()
tv.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
tv.setIndentation(0)
tv.setColumnCount(4)
tv.setFocusPolicy(QtCore.Qt.NoFocus)
tv.hideColumn(2)
tv.hideColumn(3)
tv.setHeaderLabels(['NORM', 'NAME'])
tv.header().setDefaultAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignLeft)
strlen_list = []
for k, v in testdict.items():
strlen_list.append(len(v))
TreeNodeItem = QtWidgets.QTreeWidgetItem
treeNode = TreeNodeItem(tv, k)
treeNode.setText( 0, k )
treeNode.setText( 1, v )
treeNode.setText( 2, '512' )
treeNode.setText( 3, '513' )
treeNode.setCheckState(0, QtCore.Qt.Unchecked)
widget.grid.addWidget(tv, 0, 0, QtCore.Qt.AlignTop)
label = QtWidgets.QLabel()
label.setText("Testlabel")
widget.grid.addWidget(label, 1, 0, QtCore.Qt.AlignTop)
button = QtWidgets.QPushButton('Testbutton', widget)
button.clicked.connect(test)
widget.grid.addWidget(button, 2, 0, QtCore.Qt.AlignLeft)
widget.show()
Solution
The check state change of items has absolutely nothing to do with the selection and is not directly correlated to mouse clicks, since the user could click on an item but not on its checkbox, or could press the space-bar to toggle the check state of the current item.
Assuming that you toggle the check state of items ONLY using mouse/keyboard and you will always have only one checked item at most, you can connect to the itemChanged signal and verify if any of its columns has a checked state.
Then you have to store the checked item and column so that you can later verify if any other item has changed and it's different from the previously set checked item.
class ToggleTree(QtWidgets.QTreeWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.lastToggled = None
self.itemChanged.connect(self.checkToggled)
def checkToggled(self, item):
for column in range(item.columnCount()):
if item.checkState(column):
break
else:
if self.lastToggled and self.lastToggled[0] == item:
self.lastToggled = None
return
if self.lastToggled:
oldItem, oldColumn = self.lastToggled
if oldItem != item:
# prevent recursion
self.itemChanged.disconnect(self.checkToggled)
oldItem.setCheckState(oldColumn, 0)
self.itemChanged.connect(self.checkToggled)
self.lastToggled = item, column
# ...
tv = ToggleTree()
Note: if you only need a 2-dimensional model like in your example, don't use QTreeWidget, but QTableWidget.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.