将 sourceModel() 用于 fileInfo() 时应用程序突然终止

Sudden app termination when using `sourceModel()` for `fileInfo()`

一些上下文:

我制作了一个QTreeView并设置了QFileSystemModel作为模型。有 2 个 TreeView,右边一个对应目录下的项目文件列表,左边一个用于查看该项目文件的连接文件。在帮助下,我实现了这种行为,当我单击右侧的项目文件时,其连接的文件将出现在左侧。 (我删除了存储和连接文件的机制,因为它会添加大量代码)

问题:

在添加了上面的2个TreeView之后,我又添加了一个context menu,只有一个选项,就是删除选中的文件。我认为我在左侧的第一次尝试是成功的,因为我可以看到打印在控制台中的路径。现在问题出在我试图在右侧进行时。知道这边的模型是 QSortFilterProxyModel 的子类,然后我添加了 sourceModel(),这样它将 return QFileSystemModel。但是当我尝试 运行 文件时,它只是给了我一个错误。你可以在下面看到我的实现。

def deleteFile(self, event):
        index_list = self.tree_sender.selectedIndexes()
        for index in index_list:
            if index.column() == 0:
                if isinstance(self.tree_sender.model(), ModifiedQSortFilterProxyModel)
                    fileIn = self.tree_sender.model().sourceModel().fileInfo(index) 
                else:
                    fileIn = self.tree_sender.model().fileInfo(index)

                # method above is also not working even I add sourceModel()
                # It just ends the app imediately

                path_to_delete = fileIn.absoluteFilePath()
                print(path_to_delete)

我的测试代码:

    import sys

from PyQt5.QtWidgets import QApplication, QWidget, QTreeView, QFileSystemModel, QHBoxLayout, \
    QVBoxLayout, QPushButton, QListWidget, QListWidgetItem, QMenu, QAction, QAbstractItemView
from PyQt5.QtCore import QSortFilterProxyModel, Qt
from PyQt5.QtGui import QCursor

class ModifiedQSortFilterProxyModel(QSortFilterProxyModel):

    fileInfo = None
    con_files = None
    def filterAcceptsRow(self, source_row, source_parent):
        if not self.fileInfo:
            return True

        source_index = self.sourceModel().index(source_row, 0, source_parent)
        info = self.sourceModel().fileInfo(source_index)

        if self.fileInfo.absolutePath() != info.absolutePath():
            return True
        return info.fileName() in self.con_files

    def setFilter(self, info, connected_files):
        self.fileInfo = info
        self.con_files = connected_files
        self.invalidateFilter()

class FileSystemView(QWidget):
    def __init__(self):
        super().__init__()

        appWidth = 800
        appHeight = 300
        self.setWindowTitle('File System Viewer')
        self.setGeometry(300, 300, appWidth, appHeight)
        
        dir_path = r'<your directory>'

        # -- left -- #
        self.model = QFileSystemModel()
        self.model.setRootPath(dir_path)
        self.tree =  QTreeView()
        self.tree.setModel(self.model)
        self.tree.setRootIndex(self.model.index(dir_path))
        self.tree.setColumnWidth(0, 250)
        self.tree.setAlternatingRowColors(True)
        self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
        
        self.tree.clicked.connect(self.onClicked)

        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.context_menu)

        # -- right -- #
        self.model2 = QFileSystemModel()
        self.model2.setRootPath(dir_path)
        self.model2.setReadOnly(False)

        self.filter_proxy_model = ModifiedQSortFilterProxyModel()
        self.filter_proxy_model.setSourceModel(self.model2)
        self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setDynamicSortFilter(True)
        self.filter_proxy_model.setFilterKeyColumn(0)
        root_index = self.model2.index(dir_path)
        proxy_index = self.filter_proxy_model.mapFromSource(root_index)

        self.tree2 =  QTreeView()
        self.tree2.setModel(self.filter_proxy_model)
        self.tree2.setRootIndex(proxy_index)
        self.tree2.setColumnWidth(0, 250)
        self.tree2.setAlternatingRowColors(True)
        self.tree2.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.tree2.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree2.customContextMenuRequested.connect(self.context_menu)

        # -- layout -- #
        self.tree_layout = QHBoxLayout()
        self.tree_layout.addWidget(self.tree)
        self.tree_layout.addWidget(self.tree2)

        self.setLayout(self.tree_layout)

    def context_menu(self, event):
        self.tree_sender = self.sender()
        # ^^^ I dont know how to access the treeview where context menu 
        # ^^^ is triggered so I just tried to pass it as a variable

        self.menu = QMenu(self)
        deleteAction = QAction('Delete', self)
        deleteAction.triggered.connect(lambda event: self.deleteFile(event))
        self.menu.addAction(deleteAction)
        self.menu.popup(QCursor.pos())
    
    def deleteFile(self, event):
        index_list = self.tree_sender.selectedIndexes()
        for index in index_list:
            if index.column() == 0:
                if isinstance(self.tree_sender.model(), ModifiedQSortFilterProxyModel):
                    fileIn = self.tree_sender.model().sourceModel().fileInfo(index) 
                else:
                    fileIn = self.tree_sender.model().fileInfo(index)

                # method above is also not working even I add sourceModel()
                # It just ends the app imediately

                path_to_delete = fileIn.absoluteFilePath()
                print(path_to_delete)

    def onClicked(self, index):
        print("onclick")
        connected_files = [] # list of connected files
        self.filter_proxy_model.setFilter(self.model.fileInfo(index), connected_files)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = FileSystemView()
    demo.show()
    sys.exit(app.exec_())

我的问题:是什么原因导致的错误?是 sourceModel() 实施吗?还是我做错了什么?

希望有人能指出正确的方向。

我完全忘了使用 mapToSource,但幸运的是@musicamante 指导我完成了它。我的问题现在解决了,下面给出deleteFile方法的最终实现。

def deleteFile(self, event):
        index_list = self.tree_sender.selectedIndexes()
        for index in index_list:
            if index.column() == 0:
                model = self.tree_sender.model()

                if isinstance(model, ModifiedQSortFilterProxyModel):
                    proxy_index = model.mapToSource(index)
                    fileIn = proxy_index.model().fileInfo(proxy_index)
                else:
                    fileIn = model.fileInfo(index)
    
                path_to_delete = fileIn.absoluteFilePath()
                print(path_to_delete)