Python 有没有办法在PySide或PyQt中向QListView添加节?

Python 有没有办法在PySide或PyQt中向QListView添加节?,python,qt,pyqt,pyside,Python,Qt,Pyqt,Pyside,这个问题与未回答的问题完全相同,只是我使用的是Python 我有这个 我在找这个 我正在寻找关于如何处理这个问题的提示。这是我到目前为止所考虑的 将“虚拟项”添加到模型本身。我宁愿不这样做,以保持模型中没有与视图相关的数据。我打算在此模型上添加其他视图 为每个视图添加代理模型。代理可以添加其他项并对其进行适当排序。尽管比(1)更干净,但出于同样的原因,我并不完全信服 子类QListView,但我很难理解要覆盖什么 写下我自己的观点;使用for循环和qlabel,并尽我所能与模型同步。做你该做

这个问题与未回答的问题完全相同,只是我使用的是Python

我有这个

我在找这个

我正在寻找关于如何处理这个问题的提示。这是我到目前为止所考虑的

  • 将“虚拟项”添加到模型本身。我宁愿不这样做,以保持模型中没有与视图相关的数据。我打算在此模型上添加其他视图
  • 为每个视图添加代理模型。代理可以添加其他项并对其进行适当排序。尽管比(1)更干净,但出于同样的原因,我并不完全信服
  • 子类QListView,但我很难理解要覆盖什么
  • 写下我自己的观点;使用for循环和qlabel,并尽我所能与模型同步。做你该做的
  • 救命啊

    来源

    import sys
    from PySide import QtCore, QtGui
    
    
    Label = QtCore.Qt.DisplayRole
    Section = QtCore.Qt.UserRole + 1
    
    
    class Model(QtCore.QAbstractListModel):
        def __init__(self, parent=None):
            super(Model, self).__init__(parent)
            self.items = list()
    
        def data(self, index, role):
            item = self.items[index.row()]
            if role == Label:
                return item["label"]
    
            if role == Section:
                return item["section"]
    
        def append(self, item):
            """Append item to end of model"""
            self.beginInsertRows(QtCore.QModelIndex(),
                                 self.rowCount(),
                                 self.rowCount())
    
            self.items.append(item)
            self.endInsertRows()
    
        def rowCount(self, parent=None):
            return len(self.items)
    
    app = QtGui.QApplication(sys.argv)
    model = Model()
    
    for item in ({"label": "Ben", "section": "Human"},
                 {"label": "Steve", "section": "Human"},
                 {"label": "Alpha12", "section": "Robot"},
                 {"label": "Mike", "section": "Toaster"}):
        model.append(item)
    
    view = QtGui.QListView()
    view.setWindowTitle("My View")
    view.setModel(model)
    view.show()
    
    app.exec_()
    

    更新1-其他信息 为了清楚起见,这个问题是关于QListView的,而不是关于它的替代品。原因是应用程序的其余部分正在以类似MVC的方式开发,其中一个或多个视图正在绘制一个模型中存在的唯一数据集

    此特定视图包括节,其他视图(不一定是QListView的视图)不应该知道任何有关节的信息。例如,一个视图可以是计数器,列出可用项目的数量。另一种可能是饼图,显示以字母“a”开头的项目之间的比率

    为了进一步的参考,我要寻找的正是ListView在QML中的作用

    也就是说,一个模型带有可选截面的附加委托。在这种情况下,视图不要求模型包含这些添加的成员,而是基于现有数据绘制这些成员

    例子


    更新2-正在进行的工作 好的,我已经使用QSortFilterProxyModel将额外的项目添加到视图的底部,但我很难理解:

  • 如何为它们分配相应的数据
  • 我如何在“子”项目上方将它们分类到适当的位置

  • 您需要的是一个
    QTreeWidget
    (或者
    QTreeView
    ,如果您需要单独的模型/视图,但您必须创建自己的模型才能工作)


    唯一的其他选项是使用
    QListWidget/QListView
    QItemDelegate
    以不同于标签项的方式绘制分区项。

    好的,您打算将其他视图(如饼图)连接到
    QAbstractListModel
    子体。我想这是可能的,但并不常见。因此产生了混乱。IHMO Qt模型类不是很好,如果没有表或树视图,我不会使用它们。没有什么能阻止您创建自己的模型类并从中填充
    QListWidget

    但假设您仍然希望将数据放在
    QAbstractListModel
    中。我同意将部分添加为虚拟项是一个坏主意,因此您的选项1不适用

    我认为使用代理模型是一个很好的选择。您可以将所有
    qlistView
    连接到代理,将所有其他视图(例如饼图)连接到基础源模型。然后,代理模型将节作为项目包含。我认为您只需要一个代理,因为所有列表视图的部分都是相同的

    您可以使用委托自定义单元格的呈现方式,而不是从
    QListView
    中进行子类化。查看Qt文档中的

    选项4,写你自己的观点,应该是你最后的选择。基本上,您正在推出自己的QListView版本。这是一个很大的工作,将永远不会像Qt原来的好


    希望这有帮助。

    在我看来,您的数据不是一个列表,而是一个具有两个级别的树,第一个级别按分区类型分组,第二个级别包含该分区中的所有人员。为什么不使用
    QTreeView
    并将其连接到
    QStandardItemModel
    以查看它是否适用于您(如果您有一个大型模型,则可以从
    qabstracttemmodel
    派生,但这需要做更多的工作)。不过,很遗憾,数据必须是一个列表。将附加键视为“标记”,视图将显示这些标记及其成员。项目的顺序是固定的;这意味着,如果另一个成员出现在“人”部分的底部,则会出现第二个部分,而不是将其放在第一个部分下。Ok。那么我认为选项1没有问题。您说希望使模型不受视图相关数据的影响。如果我错了,请纠正我的错误,但我明白,如果多个
    qlistView
    将连接到您的模型,它们都应该显示完全相同的信息(包括部分)。该模型的功能是将原始列表映射到可由
    QListView
    呈现的数据结构。这意味着模型是必须确定将节放置在何处的对象。>(包括节),这正是我想要避免的。其他视图不一定是QListView的视图,它们不应该知道任何关于节的信息。另一个视图可能是,例如计数器,列出可用项目的数量。或者一个饼,显示以字母“a”开头的项目之间的比率。谢谢Brendan,我在问题中添加了一些额外的信息,请看一看!谢谢@titusjan,这很有帮助。我将再次尝试代理模型。这很有效,但我遇到了更多问题@泰特斯詹,能不能请你再看一下更新后的问题?再次感谢。
    import sys
    from PySide import QtCore, QtGui
    
    
    Label = QtCore.Qt.DisplayRole
    Section = QtCore.Qt.UserRole + 1
    IsSection = QtCore.Qt.UserRole + 2
    
    
    class Item(object):
        @classmethod
        def paint(cls, painter, option, index):
            rect = QtCore.QRectF(option.rect)
    
            painter.save()
    
            if option.state & QtGui.QStyle.State_MouseOver:
                painter.fillRect(rect, QtGui.QColor("#DEE"))
    
            if option.state & QtGui.QStyle.State_Selected:
                painter.fillRect(rect, QtGui.QColor("#CDD"))
    
            painter.drawText(rect.adjusted(20, 0, 0, 0),
                             index.data(Label))
    
            painter.restore()
    
        @classmethod
        def sizeHint(cls, option, index):
            return QtCore.QSize(option.rect.width(), 20)
    
    
    class Section(object):
        @classmethod
        def paint(self, painter, option, index):
            painter.save()
            painter.setPen(QtGui.QPen(QtGui.QColor("#666")))
            painter.drawText(QtCore.QRectF(option.rect), index.data(Label))
            painter.restore()
    
        @classmethod
        def sizeHint(self, option, index):
            return QtCore.QSize(option.rect.width(), 20)
    
    
    class Delegate(QtGui.QStyledItemDelegate):
        def paint(self, painter, option, index):
            if index.data(IsSection):
                return Section.paint(painter, option, index)
            else:
                return Item.paint(painter, option, index)
    
        def sizeHint(self, option, index):
            if index.data(IsSection):
                return Section.sizeHint(option, index)
            else:
                return Item.sizeHint(option, index)
    
    
    class Model(QtCore.QAbstractListModel):
        def __init__(self, parent=None):
            super(Model, self).__init__(parent)
            self.items = list()
    
        def data(self, index, role):
            item = self.items[index.row()]
    
            return {
                Label: item["label"],
                Section: item["section"],
                IsSection: False
            }.get(role)
    
        def append(self, item):
            self.beginInsertRows(QtCore.QModelIndex(),
                                 self.rowCount(),
                                 self.rowCount())
    
            self.items.append(item)
            self.endInsertRows()
    
        def rowCount(self, parent=None):
            return len(self.items)
    
    
    class Proxy(QtGui.QSortFilterProxyModel):
        def data(self, index, role):
            if index.row() >= self.sourceModel().rowCount():
    
                return {
                    Label: "Virtual Label",
                    Section: "Virtual Section",
                    IsSection: True
                }.get(role)
    
            return self.sourceModel().data(index, role)
    
        def rowCount(self, parent):
            sections = 0
    
            prev = None
            for item in self.sourceModel().items:
                cur = item["section"]
    
                if cur != prev:
                    sections += 1
    
                prev = cur
    
            # Note: This includes 1 additional, duplicate, section
            # for the bottom item. Ordering of items in model is important.
            return self.sourceModel().rowCount() + sections
    
        def index(self, row, column, parent):
            return self.createIndex(row, column, parent)
    
        def mapToSource(self, index):
            if not index.isValid():
                return QtCore.QModelIndex()
    
            return self.sourceModel().createIndex(index.row(),
                                                  index.column(),
                                                  QtCore.QModelIndex())
    
        def parent(self, index):
            return QtCore.QModelIndex()
    
    
    app = QtGui.QApplication(sys.argv)
    model = Model()
    
    for item in ({"label": "Ben", "section": "Human"},
                 {"label": "Steve", "section": "Human"},
                 {"label": "Alpha12", "section": "Robot"},
                 {"label": "Mike", "section": "Toaster"},
                 {"label": "Steve", "section": "Human"},
                 ):
        model.append(item)
    
    proxy = Proxy()
    proxy.setSourceModel(model)
    
    delegate = Delegate()
    
    view = QtGui.QListView()
    view.setWindowTitle("My View")
    view.setModel(proxy)
    view.setItemDelegate(delegate)
    view.show()
    
    app.exec_()
    
    tree = QtGui.QTreeWidget()
    tree.setHeaderLabels(['Name'])
    
    data = ({"label": "Ben", "section": "Human"},
            {"label": "Steve", "section": "Human"},
            {"label": "Alpha12", "section": "Robot"},
            {"label": "Mike", "section": "Toaster"})
    
    sections = {}
    for d in data:
        sections.setdefault(d['section'], []).append(d['label'])
    
    for section, labels in sections.items():
        section_item = QtGui.QTreeWidgetItem(tree, [section])
        for label in labels:
            QtGui.QTreeWidgetItem(section_item, [label])