源模型更改后更新QFilterProxyModel

问题描述 投票:2回答:1

嗨我正在为带有孩子的对象创建一个对话框,一个带有QlineEdit的QTreeview用于过滤。当对话框最初出现时,它看起来像(1号)

代码如下所示。我只用重要的部分总结了它

#These are global so can be referenced from any function. and all set
#when i initialise my diaglog.

model=QtGui.QStandardItemModel()
treeview=QtGui.QTreeview()
proxymodel=QtGui.QSortFilterProxyModel(treeview)
treeview.setmodel(proxymodel)
proxymodel.setSourceModel(model)

def initialise_treeview(self):
    #This builds the treeview with a list of root nodes only
    root_nodes=["Apple","Ardvark","Ankle","Bee","Bark","Bar","Carrot"]# a list of root nodes
    for objects in root_nodes:
            item=QtGui.QStandardItem(objects)
            model.appendRow(item)

No.2显示当用户键入LineEdit文本框时要过滤的树视图

#When a user types into the search field the Treeview gets filtered via the proxymodel
QtCore.QObject.connect(LineEdit,QtCore.Signal("TextChanged(QString)")),update_filter)

def update_filter(self,text):
    #filter the model based on the text in the qlineedit
     proxymodel.setFilterRegExp(LineEdit.text());

一旦用户选择了树视图中的项目(No.3,其中Bar已被选中)。代码应该获取所有选定项目子项,将它们添加到模型中,最后展开所选节点以显示所有子项目(第4项)

#update_treeview function is called to add children to the selected item
QtCore.QObject.connect(treeview.selectionModel(),QtCore.Signal("currentChanged(QModelIndex,QmodelIndex)")),update_treeview)

def update_treeview(self,currentindex,previousindex):
    sourcemodel_index=proxymodel.mapToSource(currentindex)
    parent_item=QtGui.QStandardItem()
    #get the item from the source model
    parent_item=model.itemFromIndex(sourcemodel_index)
    for childitem in list_of_children:
        file_item=QtGui.QStandardItem(str(childitem))
        model.appendRow(file_item)

    treeview.expand(currentindex) #this doesn't work when proxymodel has been filtered

到目前为止,我有大部分工作。实际上所有这一切。除了树视图的扩展,当有一些过滤。

当没有应用过滤器时,我有它工作,但是一旦树形视图的列表被过滤它有点击中和遗漏,即树视图并不总是在右边节点扩展。

如何确保树视图在正确的索引处展开,以便在筛选文件夹列表并将文件添加到筛选列表时。如何确保将树视图扩展到正确的位置。我在Windows上使用python 2.7,Qt 4.8。

python pyqt pyqt4 qtreeview qsortfilterproxymodel
1个回答
2
投票

问题不是它没有扩展,而是受QSortProxyModel过滤器的影响,过滤器应该只应用于topLevels。我已经使用了一个新角色,如果你已经拥有它们,就不会添加更多的孩子,我也认为点击的信号最适合这种情况。

from PyQt4.QtCore import *
from PyQt4.QtGui import *

HaveChildrenRole = Qt.UserRole


class SortFilterProxyModel(QSortFilterProxyModel):
    def filterAcceptsRow(self, source_row, source_parent):
        ix = self.sourceModel().index(source_row, 0, source_parent)
        if not ix.parent().isValid(): # check if the item has no parent
            return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
        else: # as it has a parent, the filter does not apply
            return True


class Widget(QWidget):
    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.setLayout(QVBoxLayout())
        self.treeView = QTreeView(self)
        self.le = QLineEdit(self)
        self.layout().addWidget(self.treeView)
        self.layout().addWidget(self.le)
        self.model = QStandardItemModel(self)
        self.proxy = SortFilterProxyModel(self)
        self.proxy.setSourceModel(self.model)
        self.treeView.setModel(self.proxy)
        self.initialise_treeview()
        self.le.textChanged.connect(self.update_filter)
        self.treeView.clicked.connect(self.onClicked)

    def initialise_treeview(self):
        root_nodes = ["Apple", "Ardvark", "Ankle", "Bee", "Bark", "Bar", "Carrot"]  # a list of root nodes
        for obj in root_nodes:
            item = QStandardItem(obj)
            item.setData(False, HaveChildrenRole)
            self.model.appendRow(item)

    def update_filter(self, text):
        self.proxy.setFilterRegExp(text)

    def onClicked(self, ix):
        s_ix = self.proxy.mapToSource(ix)
        it = self.model.itemFromIndex(s_ix)
        if not it.data(HaveChildrenRole) and it.parent() is None:
            for children in ["A", "B", "C", "D"]:
                it.appendRow(QStandardItem(children))
                it.setData(True, HaveChildrenRole)
        self.treeView.expand(ix)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

说明:

filterAcceptsRow方法决定是否显示行,在你的情况下,应该对topLevel做出关于“Apple”,“Bee”等的决定。所以首先要确定那些项目,主要特征是他们没有父级,所以我们访问parent(),如果它是有效的,它有一个父级,如果它不是topLevel,那么该方法必须通过过滤器,而其他方法我们返回True,以便它们可见。

© www.soinside.com 2019 - 2024. All rights reserved.