PyQt5当QSortFilterProxyModel设置为mod时,QTreeView的意外行为

2024-04-18 09:33:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在python3.5上用PyQt5.7.1开发一个应用程序。我使用QTreeView以层次结构显示一些数据。我希望能够过滤这些数据,所以我使用了QSortFilterProxy模型。在

self.model = CustomTreeModel(data)
self.proxy = QSortFilterProxyModel(self.model)
self.ui.treeView.setModel(self.proxy)

这就产生了一种奇怪的行为: 默认情况下,树视图是折叠的。如果我展开任何不是第一个的项,然后单击它的任何子项,树视图的第一个项就会展开(不应该)。实际上,每当我单击任何不是第一级(根项的子项)的项时,根项的第一个子项就会展开。在

我以为我的模型有问题,但如果我不使用QSortFilterProxy模型,像这样:

^{pr2}$

treeView的行为与预期一样,第一个元素在不应该展开时不会展开

在我看来,这是PyQt5中的一个bug,但我在互联网上没有找到任何关于它的信息。相反,有一些使用qstreeview的QSortFilterProxyModel的例子,似乎没有人报告这样的问题。那么这真的是PyQt中的一个bug还是我遗漏了什么?在

下面是一个演示代码:

from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt

class CustomTreeModel(QAbstractItemModel):
    # Based on http://trevorius.com/scrapbook/uncategorized/pyqt-custom-abstractitemmodel/    

    def __init__(self, headerData, nodes):  
        QAbstractItemModel.__init__(self)  
        self._headerData = headerData
        self._root = CustomNode(None)
        for node in nodes:
            self._root.addChild(node)

    def addChild(self, in_node, in_parent=QModelIndex()):  
        if not in_parent or not in_parent.isValid():  
            parent = self._root  
        else:  
            parent = in_parent.internalPointer()  
        parent.addChild(in_node)

    def index(self, in_row, in_column, in_parent=QModelIndex()):  
        if not in_parent.isValid():  
            parent = self._root  
        else:  
            parent = in_parent.internalPointer()        
        if not QAbstractItemModel.hasIndex(self, in_row, in_column, in_parent):  
            return QModelIndex()  

        child = parent.child(in_row)  
        if child:  
            return QAbstractItemModel.createIndex(self, in_row, in_column, child)  
        else:  
            return QModelIndex()  

    def rowCount(self, in_index=QModelIndex()):  
        if in_index.isValid():  
            return in_index.internalPointer().childCount()  
        return self._root.childCount()  

    def child(self, row, index):
        if index.isValid():
            c = index.internalPointer().child(row)
            return QAbstractItemModel.createIndex(self, row, 0, c)
        return QModelIndex()

    def parent(self, in_index):  
        if in_index.isValid():  
            p = in_index.internalPointer().parent()  
            if p:  
                return QAbstractItemModel.createIndex(self, p.row(),0,p)  
        return QModelIndex()  

    def columnCount(self, in_index):  
        if in_index.isValid():  
            return in_index.internalPointer().columnCount()  
        return self._root.columnCount()  

    def data(self, in_index, role):  
        if not in_index.isValid():  
            return None  
        node = in_index.internalPointer()  
        if role == Qt.DisplayRole:  
            return node.data(in_index.column())
        return None

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if (section < 0) or (section > self.columnCount(QModelIndex())):
            return None
        if (orientation == Qt.Horizontal) and (role == Qt.DisplayRole):
            return self._headerData[section]
        return None

class CustomNode(object):
    def __init__(self, in_data):  
        self._data = in_data  
        if type(in_data) == tuple:  
            self._data = list(in_data)  
        if type(in_data) == str  or not hasattr(in_data, '__getitem__'):  
            self._data = [in_data]  

        self._columncount = len(self._data)  
        self._children = []  
        self._parent = None  
        self._row = 0

    def data(self, in_column):  
        if in_column >= 0 and in_column < len(self._data):  
            return self._data[in_column]
        return None

    def columnCount(self):  
        return self._columncount  

    def childCount(self):  
        return len(self._children)  

    def child(self, in_row):  
        if in_row >= 0 and in_row < self.childCount():  
            return self._children[in_row]
        return None

    def parent(self):  
        return self._parent  

    def row(self):  
        return self._row  

    def addChild(self, in_child):  
        in_child._parent = self
        in_child._row = len(self._children)  
        self._children.append(in_child)  
        self._columncount = max(in_child.columnCount(), self._columncount)

if __name__ == '__main__':
    import sys
    from PyQt5.QtCore import QSortFilterProxyModel  
    from PyQt5.QtWidgets import QApplication, QTreeView

    app = QApplication(sys.argv)

    header = ['Food']

    fruits = CustomNode(['Fruit'])
    fruits.addChild(CustomNode(['Apple']))
    fruits.addChild(CustomNode(['Banana']))
    fruits.addChild(CustomNode(['Orange']))
    vegetables = CustomNode(['Vegetables'])
    vegetables.addChild(CustomNode(['Carott']))
    vegetables.addChild(CustomNode(['Potato']))
    meat = CustomNode(['Meat'])
    meat.addChild(CustomNode(['Beef']))
    meat.addChild(CustomNode(['Chicken']))
    meat.addChild(CustomNode(['Pork']))

    nodes = [fruits, vegetables, meat]

    v = QTreeView()
    model = CustomTreeModel(header, nodes)
    proxy = QSortFilterProxyModel()
    proxy.setSourceModel(model)
    v.setModel(proxy)
    v.show()

    sys.exit(app.exec_())

Tags: inselfnonechilddataindexreturnif