python - 源模型更改后更新 QFilterProxyModel

标签 python pyqt pyqt4 qtreeview qsortfilterproxymodel

嗨,我正在为带有子对象的对象创建一个对话框,一个带有 QlineEdit 的 QTreeview 用于过滤。当对话框最初出现时,它看起来像 (no.1) 0_1515441319065_Screenshot from 2018-01-08 19:53:31.png

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

#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 文本框中键入内容时 TreeView 被过滤

#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());

一旦用户在 TreeView 中选择了一个项目(第 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

到目前为止,我已经完成了大部分工作。事实上这一切。除了 TreeView 的扩展之外,当有一些过滤时。

当没有应用过滤器时,我可以让它工作,但是一旦 TreeView 的列表被过滤,它就会有点偶然,即 TreeView 并不总是在正确的节点上展开。

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

最佳答案

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

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”等的决定。所以第一件事是来识别这些项目,主要特征是它们没有父级,因此我们访问 parent() ,如果它有效,则它有一个父级,如果它不是 topLevel,那么该方法必须通过过滤器并对其他过滤器返回 True,以便它们可见。

关于python - 源模型更改后更新 QFilterProxyModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48132313/

相关文章:

python - 从带有富文本的 QLabel 中获取纯文本

python - 最初按下组合框时的QComboBox鼠标按下事件PyQt4

python - pyqt:如何从 QVBoxLayout 中删除元素?

python - 无法使用 pickle 和多个模块加载文件

python - 使用 boto3 在 S3 存储桶中移动对象的最快方法

python - 在Python交互模式下使用Pyside安全吗?

python - 如何在 PyQt4 中选择性地设置文本的前景色

python - 在装饰器中访问函数属性

python - 来自一组列的 Seaborn 热图?

python - 如何让 python 机器人点击 telegram 机器人中的按钮