源模型更改后更新 QFilterProxyModel

updating QFilterProxyModel once the source model changes

您好,我正在为有子对象的对象创建一个对话框,一个带有用于过滤的 QlineEdit 的 QTreeview。当对话框最初出现时,它看起来像 (no.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());

一旦用户在树视图中选择了一个项目(第 3 条,其中已选择栏)。代码应该获取所有选中的子项,将它们添加到模型中,最后展开选中的节点以显示所有子项(第 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

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

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,因此我们访问 parent(),如果它有效,则它有一个 parent,如果它不是topLevel,那么该方法必须通过过滤器,而对于其他方法,我们 return True 以便它们可见。