Search code examples
pyqt5qtreeviewqabstractitemmodelqsortfilterproxymodel

Can`t get QTreeView model of QSortFilterProxyModel() outside of the init function


I have an application which displays JSON-file to the QTreeView. For this I created my own QJsonTreeModel(QAbstractItemModel) class for QTreeView model

In my MainWindow.py I implemented it like this:

class MainWindow(QMainWindow):
    def __init__(self, json_text: dict) -> None:
        self.tree_view = QTreeView()
        self.model = QJsonTreeModel()

        self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view.customContextMenuRequested.connect(self.open_right_click_menu)

        self.tree_view.setModel(self.model)
        self.model.load(self.json_text)

    def open_right_click_menu(self, position) -> None:
        index = self.tree_view.selectionModel().currentIndex()
        parent = index.parent()

        if not index.isValid():
            return
        # workes fine
        print(self.model.data(self.tree_view.selectedIndexes()[2], Qt.EditRole))

It works perfect but recently I needed to add search QLineEdit() field to find the input element in the tree. And for this task I found soultion with QSortFilterProxyModel(). Which I implemented like this:

class MainWindow(QMainWindow):
    def __init__(self, json_text: dict) -> None:
        self.tree_view = QTreeView()
        self.line_edit = QLineEdit()
        
        self.model = QJsonTreeModel()
        self.model.load(self.json_text)

        self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view.customContextMenuRequested.connect(self.open_right_click_menu)

        self.filter_proxy_model = QSortFilterProxyModel()
        self.filter_proxy_model.setSourceModel(self.model)
        self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) # Qt.CaseSensitive
        self.filter_proxy_model.setRecursiveFilteringEnabled(True)
        self.filter_proxy_model.setFilterKeyColumn(-1)

        self.tree_view.setModel(self.filter_proxy_model)

        self.line_edit.textChanged.connect(self.filter_proxy_model.setFilterRegExp)

    def open_right_click_menu(self, position) -> None:
        index = self.tree_view.selectionModel().currentIndex()
        parent = index.parent()

        if not index.isValid():
            return
        # not working rn. Segmentation fault
        print(self.model.data(self.tree_view.selectedIndexes()[2], Qt.EditRole))
        # also not working
        print(self.filter_proxy_model.sourceModel().data(self.tree_view.selectedIndexes()[2], Qt.EditRole))

It works fine, the input text is searched in the tree and displayed normally, but the problem is in other place. I have implemented right click menu for my QTreeView:

self.tree_view.setContextMenuPolicy(Qt.CustomContextMenu)
self.tree_view.customContextMenuRequested.connect(self.open_right_click_menu)

And in open_right_click_menu function I need to call self.model.data(self.tree_view.selectedIndexes()[2], Qt.EditRole) (index is correct, there are three columns) function or some another function of QJsonTreeModel() class which worked perfectly before adding QSortFilterProxyModel(). But after implementing QSortFilterProxyModel() I have got Segmentation fault when I am trying to call some function of QJsonTreeModel() class. Also I tried self.filter_proxy_model.sourceModel().data(self.tree_view.selectedIndexes()[2], Qt.EditRole) but it also causes Segmentation fault. Where am I wrong and how do I call functions of QJsonTreeModel() class properly?


Solution

  • I didn't find this question before I asked mine, but the problem was that I did`t map QSortFilterProxyModel back. So the solution is this:

    def open_right_click_menu(self, position) -> None:
        #  not working version
        print(self.model.data(self.tree_view.selectedIndexes()[2], Qt.EditRole))
    
        # working version
        print(self.model.data(
                self.filter_proxy_model.mapToSource(self.tree_view.selectedIndexes()[2]), Qt.EditRole))