Может ли QListWidget иметь группировки?

В настоящее время у меня есть QListWidget, который отображает много элементов, которые выбираются пользователем (и перетаскиваются). В моем приложении, когда элемент отмечен, он будет переупорядочен над непроверенными элементами. Пользователь также может перетащить / отпустить, чтобы настроить порядок отмеченных пунктов.

Проблема, с которой сталкиваются пользователи, состоит в том, что существует множество этих флажков, и они не сгруппированы логически на экране. Таким образом, я хотел бы представить группировку какой-то. Вот пример того, как это работает в настоящее время.

from PyQt4 import QtGui, QtCore
import sys

rows = [
    {'text': 'Row1', 'value': 1, 'group': 1},
    {'text': 'Row2', 'value': 2, 'group': 1},
    {'text': 'Row3', 'value': 3, 'group': 1},
    {'text': 'Row4', 'value': 4, 'group': 2},
    {'text': 'Row5', 'value': 5, 'group': 2},
    {'text': 'Row6', 'value': 6, 'group': 3},
    {'text': 'Row7', 'value': 7, 'group': 3},
    {'text': 'Row8', 'value': 8, 'group': 3},
    {'text': 'Row9', 'value': 9, 'group': 2},
    {'text': 'Row10', 'value': 10, 'group': 'testing'}
]

class MyList(QtGui.QListWidget):
    def __init__(self):
        QtGui.QListWidget.__init__(self)
        for row in rows:
            item = QtGui.QListWidgetItem(row['text'])
            # These are utilizing the ItemDataRole; 33 and 34 are among the first user defined values
            # http://pyqt.sourceforge.net/Docs/PyQt4/qt.html#ItemDataRole-enum
            item.setData(33, row['value'])
            item.setData(34, row['group'])
            item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            item.setCheckState(QtCore.Qt.Unchecked)
            self.addItem(item)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    my_list = MyList()
    my_list.show()
    sys.exit(app.exec_())

Это создает приложение, подобное этому:

пример

То, что я хочу сделать, это сгруппировать элементы, которые имеют похожие группы под сходным заголовком. Когда элемент отмечен, он появляется над группами. Первоначально это выглядит как QTreeWidget/View, за исключением того, что отмеченные элементы должны появляться за пределами существующего дерева.

Пример (вывод текста):

[CHECKED ITEMS APPEAR HERE]
Group 1
  Row1
  Row2
  Row3
Group 2
  Row4
  Row5
  Row9
Group 3
  Row6
  Row7
  Row8
Group testing
  Row10

Есть ли способ сгруппировать элементы в QListWidget, предпочтительно, чтобы можно было выбрать "заголовок" и выбрать все дочерние элементы?

1 ответ

Решение

Чтобы перечислить элементы в группах, здесь стоит вопрос: как перечислять элементы как группы в QListWidget

если элементы заголовка и обычные элементы отличаются в одном свойстве, они могут обрабатываться по-разному в слоте. Я не совсем уверен, если это так, как вы хотите. Я попытался разместить отмеченные элементы сверху и выбрать все элементы группы, щелкнув по элементу заголовка.

выбор группы по нажатию на заголовок

Выбор другого сигнала и изменение слота дает много возможностей изменить поведение. Вот мой код (я попробовал это в PyPt5, заменив QtGui на QtWidgets

from PyQt4 import QtGui, QtCore
import sys

rows = [
    {'text': 'Row1', 'value': 1, 'group': 1},
    {'text': 'Row2', 'value': 2, 'group': 1},
    {'text': 'Row3', 'value': 3, 'group': 1},
    {'text': 'Row4', 'value': 4, 'group': 2},
    {'text': 'Row5', 'value': 5, 'group': 2},
    {'text': 'Row6', 'value': 6, 'group': 3},
    {'text': 'Row7', 'value': 7, 'group': 3},
    {'text': 'Row8', 'value': 8, 'group': 3},
    {'text': 'Row9', 'value': 9, 'group': 2},
    {'text': 'Row10', 'value': 10, 'group': 'testing'}
]

grouptitles = [1, 2, 3,'testing']                       # list of grouptitles

def gruppe(d):                                  # function for sorting the itemlist
    return str(d['group'])

rows.sort(key=gruppe,reverse=False)                     # sort rows by groups

class MyList(QtGui.QListWidget):
    def __init__(self):
        QtGui.QListWidget.__init__(self)
        self.setMinimumHeight(270)
        for t in grouptitles:                           
            item = QtGui.QListWidgetItem('Group {}'.format(t))
            item.setData(33, 'header')
            item.setData(34, t)
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            self.addItem(item)
            for row in rows:
                if row['group'] == t:
                    item = QtGui.QListWidgetItem(row['text'])
                    # These are utilizing the ItemDataRole; 33 and 34 are among the first user defined values
                    # http://pyqt.sourceforge.net/Docs/PyQt4/qt.html#ItemDataRole-enum
                    item.setData(33, row['value'])
                    item.setData(34, row['group'])
                    item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
                    item.setCheckState(QtCore.Qt.Unchecked)
                    self.addItem(item)
                else:
                    pass

        self.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)   # 
        self.itemClicked.connect(self.selManager)               # select an appropriate signal

    def selManager(self, item):
        if item.data(33) == 'header':
            groupcode = item.data(34)
            for i in range(0,self.count()):
                if self.item(i).data(34) == groupcode and self.item(i).data(33) != 'header':
                    b = True if self.item(i).isSelected() == False else False
                    self.item(i).setSelected(b)
        else:           
            if item.checkState() == QtCore.Qt.Unchecked:
                item.setCheckState(QtCore.Qt.Checked)
                self.moveItem(self.currentRow(),0)    
            else:
                item.setCheckState(QtCore.Qt.Unchecked)
                text = 'Group {}'.format(item.data(34))
                new = self.indexFromItem(self.findItems(text, QtCore.Qt.MatchExactly)[0]).row() # find the row of the headeritem
                self.moveItem(self.currentRow(), new)               # moving back to group

    def moveItem(self, old, new):                       # from row(old) to row(new)
        ni = self.takeItem(old)
        self.insertItem(new,ni)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    my_list = MyList()
    my_list.show()
    sys.exit(app.exec_())
Другие вопросы по тегам