QListWidget 可以有分组吗?

Can a QListWidget have groupings?

我目前有一个 QListWidget,它显示许多用户可选择(和可拖动)的项目。在我的应用程序中,选中一个项目后,它将在未选中的项目上方重新排序。用户还可以drag/drop调整勾选项目的顺序。

用户遇到的问题是这些复选框太多了,而且它们在屏幕上没有按逻辑分组。因此,我想介绍某种分组。这是当前工作原理的示例。

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 中的项目进行分组,以便可以选择 'header' 并且可以自动选择所有 child 元素?

要在此处按组列出项目一个类似的问题:How to list items as groups in QListWidget

如果 headeritems 和 normal items 在一个 属性 中不同,它们可以在 slot 中以不同方式处理。 我不太确定,如果这是你想要的方式。我试图通过单击 headeritem 将选中的项目放在顶部,select 组中的所有项目。

通过select发送另一个信号并修改插槽,有很多可能性可以改变行为。这是我的代码(我在 PyPt5 中尝试过用 QtWidgets 替换 QtGui

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_())