如何使用带有 Qabstractitemmodel 的 QSortFilterProxyModel 隐藏第一列

How to hide the first column using a QSortFilterProxyModel with a Qabstractitemmodel

在小部件我的实现中,model 源模型(从 QAbstractItemModel 继承),proxy_model(从 QSortFilterProxyModel 继承)代理,tree(QTreeView ) 代表模型的树。

我想隐藏第一列。 我尝试使用 tree.hideColumn(0),树显示为平坦的。

qt.modeltest: FAIL! childIndex != childIndex1 () returned FALSE

我很清楚在树模型中,子索引必须附加到单个父索引(第一列)。 但是,如果第一列被过滤,如果源模型的父子关系没有被代理保留,我应该如何隐藏代理模型中的第一列?我觉得这是代理的“错误”,或者我错过了什么!

有谁知道 filtering/hiding 树视图中第一列的正确方法而不丢失 parent/child 信息,并且仍然验证 qmodel 实现?

谢谢!

正确且正确的实现至少需要代理为 second 列的父级创建索引,需要正确实现 index()parent()mapToSource()mapFromSource()。对于可能非常棘手的树模型。

如果源模型不是太复杂并且其所有功能都已正确实现,可能的解决方法是覆盖代理的 data()(和 headerData)并始终 return 下一列的兄弟。

以下测试是使用简单的 QStandardItemModel 完成的,但我不认为使用 QAbstractItemModel 应该有任何不同,只要它正确实现即可。

from PyQt5 import QtCore, QtGui, QtWidgets

class ColumnSwapProxy(QtCore.QSortFilterProxyModel):
    def data(self, index, role=QtCore.Qt.DisplayRole):
        return super().data(index.sibling(index.row(), index.column() + 1), role)

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal:
            section += 1
        return super().headerData(section, orientation, role)

class Test(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)

        self.combo = QtWidgets.QComboBox()
        layout.addWidget(self.combo)

        self.tree = QtWidgets.QTreeView()
        layout.addWidget(self.tree)
        self.model = QtGui.QStandardItemModel()
        self.createTree(self.model.invisibleRootItem())

        self.tree.setModel(self.model)
        self.model.setHorizontalHeaderLabels(
            ['Root', 'Fake root'] + ['Col {}'.format(c) for c in range(2, 6)])
        self.tree.header().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

        self.proxy = ColumnSwapProxy()
        self.proxy.setSourceModel(self.model)

        self.combo.addItem('Base model', self.model)
        self.combo.addItem('First column hidden', self.proxy)
        self.combo.currentIndexChanged.connect(self.setModel)

    def setModel(self):
        model = self.combo.currentData()
        self.tree.setModel(model)
        lastColumn = self.model.columnCount() - 1
        self.tree.header().setSectionHidden(lastColumn, model == self.proxy)

    def createTree(self, parent, level=0):
        for r in range(10):
            first = QtGui.QStandardItem('Root {} (level {})'.format(level + 1, r + 1))
            if level < 2 and not r & 3:
                self.createTree(first, level + 1)
            row = [first]
            for c in range(5):
                row.append(QtGui.QStandardItem(
                    'Column {} (level {})'.format(c + 2, level + 1)))
            parent.appendRow(row)


import sys
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.show()
sys.exit(app.exec_())