如何使用 QFileDialog 过滤可执行文件? 跨平台解决方案

问题描述

documentation for QFileDialog.getOpenFileName 没有提供有关如何使用 const QString &filter = QString() 仅过滤可执行文件的任何线索。这是我使用 PyQt5 的操作代码

from PyQt5.QtWidgets import QAction,QFileDialog
from PyQt5.QtCore import QDir
from os import path


class OpenSourcePortAction(QAction):

    def __init__(self,widget,setSourcePort,config,saveSourcePortPath):
        super().__init__('&Open Source Port',widget)
        self.widget = widget
        self.setShortcut('Ctrl+O')
        self.setStatusTip('Select a source port')
        self.triggered.connect(self._open)
        self.setSourcePort = setSourcePort
        self.config = config
        self.saveSourcePortPath = saveSourcePortPath

    def _open(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName,_ = QFileDialog.getopenFileName(
            self.widget,"Select a source port",self.config.get("sourcePortDir"),"Source Ports (gzdoom zandronum)",options=options)
        if fileName:
            self.saveSourcePortPath(fileName)
            self.setSourcePort(fileName)

在 linux 上,自然地,我没有可执行文件文件扩展名,但我需要在 windows 上过滤 .exe 扩展名(我打算为其提供一个版本)。此外,没有允许 QDir::Executable 的重载方法。如何在仅过滤可执行文件的同时使用 QFileDialog.getopenFileName,无论它在哪个平台上运行?

解决方法

如果您想要更个性化的过滤器,那么您必须使用 proxyModel,但为此您不能使用 getOpenFileName 方法,因为 QFileDialog 实例不容易访问,因为它是一个静态方法。

class ExecutableFilterModel(QSortFilterProxyModel):
    def filterAcceptsRow(self,source_row,source_index):
        if isinstance(self.sourceModel(),QFileSystemModel):
            index = self.sourceModel().index(source_row,source_index)
            fi = self.sourceModel().fileInfo(index)
            return fi.isDir() or fi.isExecutable()
        return super().filterAcceptsRow(source_row,source_index)


class OpenSourcePortAction(QAction):
    def __init__(self,widget,setSourcePort,config,saveSourcePortPath):
        super().__init__("&Open Source Port",widget)
        self.widget = widget
        self.setShortcut("Ctrl+O")
        self.setStatusTip("Select a source port")
        self.triggered.connect(self._open)
        self.setSourcePort = setSourcePort
        self.config = config
        self.saveSourcePortPath = saveSourcePortPath

    def _open(self):
        proxy_model = ExecutableFilterModel()
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        dialog = QFileDialog(
            self.widget,"Select a source port",self.config.get("sourcePortDir")
        )
        dialog.setOptions(options)
        dialog.setProxyModel(proxy_model)
        if dialog.exec_() == QDialog.Accepted:
            filename = dialog.selectedUrls()[0].toLocalFile()
            self.saveSourcePortPath(fileName)
            self.setSourcePort(fileName)