在 Firefox 中,如果我下载文件,会有一个文件夹图标“在文件夹中显示”:
...单击后,将在下载目录中打开本机操作系统文件资源管理器,并选择目标下载文件:
我想要同样类型的功能 - 除了我希望在 PyQt5 应用程序中使用它,当打开 QFileDialog 时,在选择目标文件时激活的右键单击上下文菜单中选择一个操作;例如通过 PyQt5 示例(如下),我可以获得这个 Qt5 对话框:
...所以,当我右键单击目标文件(如图像中的
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_())
正如评论中所指出的,没有内置的 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()