通过在 PyQt5 中右键单击从本机文件资源管理器中的 QFileDialog 打开文件?

问题描述 投票:0回答:1

在 Firefox 中,如果我下载文件,会有一个文件夹图标“在文件夹中显示”:

Firefox Show in Folder

...单击后,将在下载目录中打开本机操作系统文件资源管理器,并选择目标下载文件:

Show in Folder opened in native File Explorer

我想要同样类型的功能 - 除了我希望在 PyQt5 应用程序中使用它,当打开 QFileDialog 时,在选择目标文件时激活的右键单击上下文菜单中选择一个操作;例如通过 PyQt5 示例(如下),我可以获得这个 Qt5 对话框:

Qt5 QFileDialog

...所以,当我右键单击目标文件(如图像中的

test.txt
)时,我希望将“在文件夹中显示”操作添加到上下文菜单中,当选择它时,我' d 就像在包含目标文件的目录中打开的本机文件资源管理器一样,并选择目标文件 - 就像 Firefox 所做的那样。

如何在 PyQt5 中做到这一点?

示例代码:

# started from https://pythonspot.com/pyqt5-file-dialog/
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog
from PyQt5.QtGui import QIcon

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 file dialogs - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.openFileNameDialog()

        self.show()

    def openFileNameDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","Text Files (*.txt)", options=options)
        if fileName:
            print(fileName)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())
python pyqt5 qt5
1个回答
0
投票

正如评论中所指出的,没有内置的 Qt 支持。在系统文件管理器中打开和选择文件非常棘手,并且没有完美的跨平台解决方案。但是,如果您不想开发自己的解决方案,有一个 Python show-in-file-manager 包 可以完成合理的工作。然后它仍然是

QFileDialog
的子类并重新实现上下文菜单处理。 (注意:这意味着将不再可能使用像
getOpenFileName
这样的静态函数,它使用
QFileDialog
的内部 Qt 实例 - 当然,除非您也选择重新实现这些函数)。

这是一个基本演示(仅在 Linux 上测试):

from PyQt5.QtCore import (
    QFile, QFileDevice,
    )
from PyQt5.QtWidgets import (
    QApplication, QListView, QTreeView, QFileSystemModel, QToolButton,
    QWidget, QFileDialog, QAction, QMenu, QPushButton, QVBoxLayout,
    QMessageBox,
    )
# from PyQt6.QtCore import (
#     QFile, QFileDevice,
#     )
# from PyQt6.QtGui import (
#     QAction, QFileSystemModel,
#     )
# from PyQt6.QtWidgets import (
#     QApplication, QListView, QTreeView, QToolButton, QMessageBox,
#     QWidget, QFileDialog, QMenu, QPushButton, QVBoxLayout,
#     )

class FileDialog(QFileDialog):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setOptions(QFileDialog.Option.DontUseNativeDialog)
        self._list_view = self.findChild(QListView, 'listView')
        self._list_view.customContextMenuRequested.disconnect()
        self._list_view.customContextMenuRequested.connect(
            self.showContextMenu)
        self._tree_view = self.findChild(QTreeView, 'treeView')
        self._tree_view.customContextMenuRequested.disconnect()
        self._tree_view.customContextMenuRequested.connect(
            self.showContextMenu)
        self._rename_action = self.findChild(QAction, 'qt_rename_action')
        self._delete_action = self.findChild(QAction, 'qt_delete_action')
        self._hidden_action = self.findChild(QAction, 'qt_show_hidden_action')
        self._folder_action = self.findChild(QAction, 'qt_new_folder_action')
        self._folder_button = self.findChild(QToolButton, 'newFolderButton')
        self._show_in_action = QAction('Show In &Folder')
        self._show_in_action.triggered.connect(self.showInFolder)
        self._model = self.findChild(QFileSystemModel, 'qt_filesystem_model')

    def showContextMenu(self, position):
        if self.viewMode() == QFileDialog.ViewMode.Detail:
            view = self._tree_view
        else:
            view = self._list_view
        index = view.indexAt(position)
        index = index.sibling(index.row(), 0)
        if (proxy := self.proxyModel()) is not None:
            index = proxy.mapToSource(index)
        menu = QMenu(view)
        if index.isValid():
            menu.addAction(self._show_in_action)
            menu.addSeparator()
            permissions = QFileDevice.Permission(index.parent().data(
                QFileSystemModel.Roles.FilePermissions))
            enable = bool(not self._model.isReadOnly() and
                permissions & QFileDevice.Permission.WriteUser)
            self._rename_action.setEnabled(enable)
            menu.addAction(self._rename_action)
            self._delete_action.setEnabled(enable)
            menu.addAction(self._delete_action)
            menu.addSeparator()
        menu.addAction(self._hidden_action)
        if self._folder_button.isVisible():
            self._folder_action.setEnabled(self._folder_button.isEnabled())
            menu.addAction(self._folder_action)
        menu.exec(view.viewport().mapToGlobal(position))

    def showInFolder(self):
        if files := self.selectedFiles():
            try:
                from showinfm import show_in_file_manager
            except ImportError:
                QMessageBox.warning(self, 'Show In Folder', (
                    '<br>Please install <a href="https://pypi.org/'
                    'project/show-in-file-manager/">'
                    'show_in_file_manager</a>.<br>'
                    ))
            else:
                show_in_file_manager(files)

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.button = QPushButton('Open File')
        self.button.clicked.connect(self.openFileNameDialog)
        layout = QVBoxLayout(self)
        layout.addWidget(self.button)
        self.dialog = FileDialog(self)

    def openFileNameDialog(self):
        self.dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
        self.dialog.setNameFilter('Text Files (*.txt);;All Files(*)')
        self.dialog.open()

if __name__ == '__main__':

    app = QApplication(['Test'])
    window = Window()
    window.setGeometry(600, 100, 200, 50)
    window.show()
    app.exec()
© www.soinside.com 2019 - 2024. All rights reserved.