Отметить/снять отметку с выбранных элементов дерева

Как я могу сделать так, чтобы когда пользователь нажимал на флажок в выбранных элементах, он изменял все выбранные элементы в дереве, чтобы они соответствовали состоянию установленного флажка? Элемент, по которому щелкнули.

Например, когда я нажимаю Джейсона, все остальные выбранные элементы также должны быть проверены. Однако вместо этого в настоящее время происходит то, что Джейсон становится единственным выбранным и проверенным элементом.

Прежде чем нажать на Джейсона:

введите здесь описание изображения

Результат в настоящее время после нажатия Джейсона:

введите здесь описание изображения

Что я хотел бы сделать:

введите здесь описание изображения

import sys
import os
from PySide import QtGui, QtCore


class Example(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)
        self.resize(300, 300)
        self.setWindowTitle('Example')

        self.ui_items = QtGui.QTreeView()
        self.ui_items.sortByColumn(1, QtCore.Qt.AscendingOrder)
        self.ui_items.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.ui_items.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui_items.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.ui_items.setModel(QtGui.QStandardItemModel())

        grid = QtGui.QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(self.ui_items, 0, 0)
        self.setLayout(grid)
        self.setLayout(grid)

        self.create_model()


    def create_model(self):
        model = self.ui_items.model()
        model.clear()
        model.setHorizontalHeaderLabels(['Items'])
        self.ui_items.sortByColumn(0, QtCore.Qt.AscendingOrder)

        data = {
            'Family 01': ['Amy', 'Kevin'],
            'Family 02': ['Sarah', 'Jason', 'Abby'],
            'Family 03': ['Michelle', 'Mike', 'Scott', 'Allie']
        }

        for k, v in data.items():
            root = []

            # family
            root_node = QtGui.QStandardItem()
            root_node.setData(k, role=QtCore.Qt.DisplayRole)
            root.append(root_node)

            # children
            for child in v:

                row = []
                row_node = QtGui.QStandardItem()
                row_node.setData(child, role=QtCore.Qt.DisplayRole)
                row_node.setCheckable(True)
                row.append(row_node)
                root_node.appendRow(row)

            model.appendRow(root)

        self.ui_items.expandAll()
        self.ui_items.resizeColumnToContents(0)


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

person JokerMartini    schedule 10.09.2018    source источник
comment
вы могли бы лучше объяснить себя, насколько я понимаю, предполагая, что есть некоторые выбранные элементы, и вы нажимаете флажок, принадлежащий некоторым из этих элементов, тогда все остальные элементы должны иметь такой же статус. Я не ошибаюсь?   -  person eyllanesc    schedule 10.09.2018
comment
обновляется по вашему запросу с изображениями. дайте мне знать, если это не имеет смысла   -  person JokerMartini    schedule 10.09.2018
comment
Я бы посчитал этот плохой дизайн пользовательского интерфейса, потому что он противоречит тому, как работает любой другой древовидный интерфейс. Обычный способ сделать это — выбрать отдельную кнопку с пометкой «галочка» или аналогичную ей.   -  person three_pineapples    schedule 11.09.2018
comment
@three_pineapples не был уверен, что в вопросе кто-то жаловался на мой дизайн. Просил помощи по функциональности, которую я хотел, вот и все.   -  person JokerMartini    schedule 11.09.2018


Ответы (1)


Первым шагом является подключение к сигналу, который излучается при изменении состояния элемента.

Это может быть достигнуто за счет:

model = self.ui_items.model()
model.itemChanged.connect(self.handle_statechange)

Эти строки должны быть вставлены после вашей команды setModel(). handle_statechange — это имя метода, который вам нужно будет определить:

def handle_statechange(self, checked_item):
    state = checked_item.checkState()
    indices = self.ui_items.selectedIndexes()
    for idx in indices:
        item = idx.model().itemFromIndex(idx)
        item.setCheckState(state)

Изменить: Eyllanesc отмечает, что нажатие на флажок отменяет выбор всех элементов, кроме того, на котором установлен флажок. Это нормальное поведение, которого вы как пользователь можете избежать, удерживая нажатой кнопку «Ctrl». Я не знаю, как вы можете переопределить это стандартное поведение как программист.

person Frank from Frankfurt    schedule 14.09.2018
comment
Вы пробовали все случаи? Например, в некоторых моих тестах у меня было 3 выбранных элемента, и если я нажимаю на флажок, он отменяет выбор других элементов, и когда он достигает слота selectedIndexes(), у него есть только один элемент, который был нажат. - person eyllanesc; 14.09.2018
comment
@eyllanesc: я могу подтвердить, что вы теряете множественный выбор, когда устанавливаете флажок (я добавил несколько строк к своему ответу). Однако я не могу воспроизвести ваше наблюдение о том, что в selectedIndexes() возвращается только один индекс. - person Frank from Frankfurt; 17.09.2018
comment
Если вы хотите воспроизвести проблему, вы можете сделать следующее: выберите 3 элемента, назовем их A, B и C, и в первом тесте вы проверили в A, во втором тесте выберите те же элементы в том же порядке и теперь вы проверили в B, и для третьего случая та же процедура, но теперь вы проверили в C. - person eyllanesc; 17.09.2018
comment
Я не могу воспроизвести вашу проблему. print(len(indices) всегда возвращает ожидаемое значение. - person Frank from Frankfurt; 17.09.2018