具有多个 header 的 QStandardItemModel - 将 QTreeView header 与模型分离

QStandardItemModel with multiple headers - decouple QTreeView header from model

我有一个 QStandardItemModel,在不同的视图中需要不同的水平 header 标签。

我无法找到有关如何以这种方式将 QTreeView 的 header 与模型分离的信息。这可能吗?

请参阅下面的简单代码示例。


在这个例子中 - 我们有 ItemTypeA,这是我们的顶级项目,它的水平轴代表属性“名称 | 插值 | 规范化”。

ItemTypeA (ItemTypeB) 的 children 在水平轴上有代表“名称 | 相乘”的项目

TreeViewA 显示所有内容,TreeViewB 仅显示所选 Top Level Item 的 children(本例中未实现选择连接)。

from PySide.QtGui import *
from PySide.QtCore import *

class MyModel(QStandardItemModel):

    def __init__(self):
        super(MyModel, self).__init__()
        iroot = self.invisibleRootItem()

        self.setHorizontalHeaderLabels(['Name', 'Interpolation', 'Normalize'])

    def newTopLevelItem(self, name = 'myTopLevelItem'):
        item = ItemTypeA(name)
        root_item = self.invisibleRootItem()
        root_item.appendRow([item]+item.settingItems())
        return item


class ItemTypeA(QStandardItem):
    def __init__(self, *args, **kwargs):
        super(ItemTypeA, self).__init__(*args, **kwargs)

        self.s_interpolation =QStandardItem('0')
        self.s_normalize = QStandardItem('False')

    def settingItems(self):
        return [
            self.s_interpolation,
            self.s_normalize
        ]
        
    def newChildItem(self, name = 'newChildItem'):
        childItem = ItemTypeB( name )
        self.appendRow( [childItem]+childItem.settingItems() )


class ItemTypeB(QStandardItem):
    def __init__(self, *args, **kwargs):
        super(ItemTypeB, self).__init__(*args, **kwargs)
        
        self.s_multiply = QStandardItem('1.0')

    def settingItems(self):
        return [
            self.s_multiply,
        ]
        

class TreeViewA(QTreeView):
    '''
    THIS VIEW Needs the Headers:
        Item Name | Interpolation | Normalize
    '''
    def __init__(self):
        super(TreeViewA, self).__init__()
        model = MyModel()
        self.setModel(model)
        
        newItem = model.newTopLevelItem()
        newItem.newChildItem()

class TreeViewB(QTreeView):
    '''
    THIS VIEW Needs the Headers:
        Item Name | Multiply
    '''
    def __init__(self, sourceView):
        super(TreeViewB, self).__init__()
        model = sourceView.model()
        self.setModel(model)
        self.setRootIndex(model.index(0,0))
        

class MyWidget(QWidget):
    
    def __init__(self):
        super(MyWidget, self).__init__()
        layout = QHBoxLayout()
        viewA = TreeViewA()
        viewB = TreeViewB(viewA)
        layout.addWidget(viewA)
        layout.addWidget(viewB)
        self.setLayout(layout)

widget = MyWidget()
widget.show()

想法?

这些情况的解决方案是使用 QIdentityProxyModel,但 PySide 和 PySide 中不存在此 class,因此我们必须使用类似的 class,例如 QSortFilterProxyModel 并覆盖 headerData 方法。

...

class HeaderProxyModel(QSortFilterProxyModel):
    def __init__(self, *args, **kwargs):
        QSortFilterProxyModel.__init__(self, *args, **kwargs)
        self.labels = []
    def setHeaderLabels(self, labels):
        self.labels = labels
    def headerData(self, section,orientation, role = Qt.DisplayRole):
        if orientation == Qt.Horizontal and 0 <= section < self.columnCount() and role==Qt.DisplayRole and section < len(self.labels) :
            return self.labels[section]
        return QSortFilterProxyModel.headerData(self, section, orientation, role)

class TreeViewB(QTreeView):
    '''
    THIS VIEW Needs the Headers:
        Item Name | Multiply
    '''
    def __init__(self, sourceView):
        super(TreeViewB, self).__init__()
        model = sourceView.model()
        proxy = HeaderProxyModel()
        proxy.setSourceModel(model)
        proxy.setHeaderLabels(["Name", "Multiply"])
        self.setModel(proxy)
        self.setRootIndex(proxy.index(0,0))
...