【问题标题】:updating QFilterProxyModel once the source model changes源模型更改后更新 QFilterProxyModel
【发布时间】:2018-06-16 08:53:24
【问题描述】:

您好,我正在为带有子对象的对象创建一个对话框,一个带有 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 位,已选择 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。

【问题讨论】:

  • initialise treeview() 生成目录树?对我来说,我得到了一个目录列表。
  • @eyllanesc,你是对的,它获取目录列表,然后我将它们添加到模型中,并将模型附加到树视图。我的问题是第二部分。更新模型后,如何获得正确的索引以展开。
  • 您的图像有点混乱,因为我希望看到C:, D:, E: 内部的目录及其子目录,例如:C:, D:, E:, Users, Desktop, ...,根据我对您的解释的理解,顶层您的 QTreeView 是目录,子项将是文件。假设以上我理解您希望您能够在单击父目录时显示该目录的子目录。我说的对吗?

标签: python pyqt pyqt4 qtreeview qsortfilterproxymodel


【解决方案1】:

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

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 方法决定是否显示该行,在您的情况下,应该对“Apple”、“Bee”等的 topLevel 做出决定。所以首先要识别这些项目和主要特点是它们没有父级,所以我们访问parent(),如果它是有效的,它有一个父级,如果它不是顶层,那么该方法必须通过过滤器,我们返回 True 其他方法它们是可见的。

【讨论】:

  • 谢谢。我会尽快尝试,但你能解释一下 filterAcceptsRow 的实际作用吗?我不清楚它在做什么。
  • 谢谢,为我工作,感谢您的解释
猜你喜欢
  • 2015-08-11
  • 1970-01-01
  • 2019-08-23
  • 2012-01-16
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多