使用“sourceModel()”作为“fileInfo()”时应用程序突然终止

发布于 2025-01-21 03:12:39 字数 6053 浏览 2 评论 0原文

某些上下文:

我做了qtreeview,set qfilesystemmodel作为其模型。有2个树景,右边的一个在目录中的项目文件列表中对应,左侧一个用于该项目文件的连接文件的视图。有了帮助,我已经实现了这种行为,当我在右侧单击项目文件时,其连接的文件将出现在左侧。 (我删除了存储的机制和连接的文件,因为它将添加大量代码)

“在此处输入图像描述”

问题:

在添加上面的2个TreeViews之后,我添加了一个上下文菜单只有一个选项,即删除所选文件。我认为我的第一次尝试在左侧是成功的,因为我可以看到控制台上印刷的路径。现在,当我尝试在右侧进行操作时,问题就在于。知道这一侧的模型是从QSortFilterProxymodel subseral子分类的,然后我添加了sourcemodel(),以便它将返回qfilesystemmodelmodel。但是,当我尝试运行文件时,它只是给了我一个错误。您可以在下面看到我的实现。

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()实现吗?还是我做错了什么?

我希望有人可以指出正确的方向。

Some context:

I made a QTreeView and set QFileSystemModel as its model. There are 2 TreeViews, the one on the right corresponds in the list of the project files in a directory, and the left one serves for the view of the connected files for that project file. With help, I've implemented this behavior where when I click on a project file on the right side, its connected files will appear on the left side. (I removed the mechanism of storing and the connected files as it will add a ton of code)

enter image description here

The problem:

After adding the 2 TreeViews above, I then added a context menu with only one option, which is to delete the selected files. I think my first attempt which is on the left side is successful because I can see the path printed in the console. Now the problem lies when I tried to do it on the right side. Knowing that the model in this side is subclassed from the QSortFilterProxyModel, I then added the sourceModel() so that it will return the QFileSystemModel. But when I tried to run the file, It just gives me an error. You can see my implementation below.

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)

My Testing Code:

    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_())

My Question: What causes the error? is it sourceModel() implementation? or I did something very wrong?

I hope someone can point me out to the right direction.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦情居士 2025-01-28 03:12:39

我完全忘记使用 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)

I totally forgot to use mapToSource, but thankfully @musicamante guided me through it. My question is now solved, and the final implementation of the deleteFile method is given below.

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文