как сменить Qt.ItemIsAutoTristate на Qt.ItemIsUserCheckable во всех элементах дерева qtreewidget

Рейтинг: 0Ответов: 1Опубликовано: 30.05.2023

Имеется дерево qtreewidget с разным уровнем потомков и количеством узлов. При его построении для каждого элемента создается флажок для его выбора с флагом элемента Qt.ItemIsAutoTristate. Так же имеются две radiobutton по переключению которых вызывается метод rechecking() для переопределения флагов у каждого элемента дерева, например чтобы сменить на Qt.ItemIsUserCheckable или обратно. Это нужно для удобства выбора флажков: чтобы можно было выделить родителя и кучу его потомков одним кликом, а потом снять выделение только с родителя и при снятии флажков с потомков состояние родителя не изменялось бы. Так вот этот метод отрабатывает, однако понятно что при этом ничего не изменяется, выбор флажков остается всегда как при Qt.ItemIsAutoTristate, то есть на Qt.ItemIsUserCheckable не изменяется. Куда копать не пойму.

Вот минимальный код для проверки:


from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *


class TreeViewDemo(QWidget):
    def __init__(self):
        super(TreeViewDemo, self).__init__()

        self.groupBox = QtWidgets.QGroupBox()
        self.groupBox.setMinimumSize(QtCore.QSize(0, 90))
        self.groupBox.setObjectName("groupBox")
        self.radioButton = QtWidgets.QRadioButton(self.groupBox)
        self.radioButton.setGeometry(QtCore.QRect(20, 20, 150, 25))
        self.radioButton.setChecked(True)
        self.radioButton_2 = QtWidgets.QRadioButton(self.groupBox)
        self.radioButton_2.setGeometry(QtCore.QRect(20, 50, 150, 25))
        self.radioButton.setText("Множественный выбор")
        self.radioButton_2.setText("Единичный выбор")

        self.treeWidget = QTreeWidget()
        self.treeWidget.setColumnCount(1)
        self.treeWidget.setHeaderLabels(['Items'])

        for i in range(3):
            parent = QTreeWidgetItem(self.treeWidget)
            parent.setText(0, f'Item {i}')
            flags = parent.flags() | Qt.ItemIsAutoTristate
            parent.setFlags(flags)
            parent.setCheckState(0, Qt.Unchecked)
            self.treeWidget.addTopLevelItem(parent)

        self.add_child_button = QPushButton('Add Child')
        self.add_child_button.clicked.connect(self.add_child)

        self.radioButton.clicked.connect(self.rechecking)
        self.radioButton_2.clicked.connect(self.rechecking)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.treeWidget)
        main_layout.addWidget(self.add_child_button)
        main_layout.addWidget(self.groupBox)

        self.setLayout(main_layout)

    def add_child(self):
        selected_item = self.treeWidget.currentItem()
        child = QTreeWidgetItem()
        child.setText(0, 'Child Item')
        flags = child.flags() | Qt.ItemIsAutoTristate
        child.setFlags(flags)
        child.setCheckState(0, Qt.Unchecked)
        selected_item.addChild(child)

    def rechecking(self):

        def recurse(parent_item):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                grand_children = child.childCount()

                if self.radioButton.isChecked():
                    print('кнопка 1')
                    flags = Qt.ItemIsAutoTristate
                    if grand_children > 0:
                        child.setFlags(child.flags() | flags)
                        recurse(child)
                    child.setFlags(child.flags() | flags)

                if self.radioButton_2.isChecked():
                    print('кнопка 2')
                    flags = Qt.ItemIsUserCheckable
                    if grand_children > 0:
                        child.setFlags(child.flags() | flags)
                        recurse(child)
                    child.setFlags(child.flags() | flags)

                child.setFlags(child.flags() | flags)
            parent_item.setFlags(parent_item.flags() | flags)

        recurse(self.treeWidget.invisibleRootItem())


if __name__ == '__main__':
    app = QApplication([])
    window = TreeViewDemo()
    window.show()
    app.exec_()

Ответы

▲ 0

В итоге не стал заморачиваться, сделал проще: организовал все через контекстное меню, сделал в нем два пункта : "Выбрать всю ветку" и "Снять выделение". А по умолчанию построение дерева сделал с флагом Qt.ItemIsUserCheckable. Теперь можно клюкнуть по любому родительскому элементу и через контекстное меню установить состояние флажков всех потомков.