QTreeView not updating after inserting new data in QAbstractItemModel with a QSortFilterProxyModel

323 views Asked by At

I have a TreeView which is displaying items from an AbstractItemModel.. Now I wanted to add extra Filter functionality to my application, but somehow, the data is not visible in the TreeView (after calling newData()). How does the interaction between the QAbstractItemModel and the QSortFilterProxyModel happens? what should the QSortFilterProxyModel knows more the the setSource(QAbstractItemModel)

Here my code (copied from: https://stackoverflow.com/a/60910989/298487)

import logging
import sys
from PySide6 import QtCore, QtWidgets
from PySide6.QtCore import QSortFilterProxyModel

class DBObject:
    def __init__(self, name, parent, children=None):
        self.name = name
        self.parent = parent
        self.children = children or list()

    def __repr__(self):
        return f"name: {self.name}, parent: {self.parent.name if self.parent is not None else '-'}"


class Model(QtCore.QAbstractItemModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._root = DBObject("root", None)

    def newData(self):
        items = ["foo", "bar", "baz"]
        for x in items:
            child = DBObject(x + "0", self._root)
            self._root.children.append(child)
            for y in items:
                child.children.append(DBObject(y + "1", child))

    def columnCount(self, parent=QtCore.QModelIndex()):
        return 1

    def rowCount(self, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            return 1

        parentItem = parent.internalPointer()
        rowCount = len(parentItem.children)
        logging.info(f"rowCount({parentItem}): rowCount={rowCount}")
        return rowCount

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()

        item = index.internalPointer()
        parentItem = item.parent

        logging.info(f"parent({item}): parent={parentItem}")
        if parentItem is None:
            return QtCore.QModelIndex()
        else:
            if parentItem.parent is None:
                return self.createIndex(0, 0, parentItem)
            else:
                return self.createIndex(parentItem.parent.children.index(parentItem), 0, parentItem)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        if not parent.isValid():
            if row != 0 or column != 0:
                return QtCore.QModelIndex()
            else:
                logging.info(f"index({row}, {column}, None): index={self._root}")
                return self.createIndex(0, 0, self._root)

        parentItem = parent.internalPointer()

        if 0 <= row < len(parentItem.children):
            logging.info(f"index({row}, {column}, {parentItem}): index={parentItem.children[row]}")
            return self.createIndex(row, column, parentItem.children[row])
        else:
            logging.info(f"index({row}, {column}, {parentItem}): index=None")
            return QtCore.QModelIndex()

    def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
        if not index.isValid():
            return None

    item = index.internalPointer()

    if role == QtCore.Qt.ItemDataRole.DisplayRole:
        return item.name
    else:
        return None

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.ItemFlag.NoItemFlags

        return (
            QtCore.Qt.ItemFlag.ItemIsEnabled
            | QtCore.Qt.ItemFlag.ItemIsSelectable)


class ProxyModel(QSortFilterProxyModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFilterKeyColumn(0)
        self.setRecursiveFilteringEnabled(True)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setMinimumSize(640, 480)

        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)

        layout = QtWidgets.QVBoxLayout(centralWidget)

        self._treeView = QtWidgets.QTreeView(self)
        layout.addWidget(self._treeView)

        self._model = Model()
        self._proxyModel = ProxyModel()
        self._proxyModel.setSourceModel(self._model)
        # this line will not work
        self._treeView.setModel(self._proxyModel)
        # if i replace it with this line, it is working
        # but the filtering will not work
        self._treeView.setModel(self._model)

        self._proxyModel.setFilterFixedString("bar1")

        button = QtWidgets.QPushButton("Add")
        layout.addWidget(button)

        button.clicked.connect(self._Clicked)

    def _Clicked(self):
        self._model.newData()
        self._treeView.expandAll()

def main():
    app = QtWidgets.QApplication(sys.argv)

    mainWindow = MainWindow()
    mainWindow.show()
    app.exec()

if __name__ == "__main__":
    main()
0

There are 0 answers