防止 QFileDialog 中的文件操作,例如复制、查看、删除等

Posted

技术标签:

【中文标题】防止 QFileDialog 中的文件操作,例如复制、查看、删除等【英文标题】:Preventing file actions in QFileDialog, such as copying, viewing, deleting, etc 【发布时间】:2016-03-23 12:00:27 【问题描述】:

我们正在考虑在 Azure 服务器上部署 PyQt 应用程序,该应用程序运行良好,尽管响应用户操作有点慢。

但是,我们有一个问题,那就是 QFileDialog 几乎允许任何探索操作:将文件从虚拟机复制到用户的本地驱动器,在记事本的“程序文件 (x86)”中打开一个文件,等等

已经考虑过的方法:

    由于 python 应用程序必须具有读写权限 在“程序文件(x86)”下运行,我们不能使用文件权限来 控制访问。

    我们可以将 Python 变成一个难以理解的 .exe,但这可能 仍然可以使用文件对话框中的上下文菜单进行复制。

    我们可以使用文件过滤器然后隐藏它们,所以你只能 查看(并弄乱)相关文件,但用户仍然可以 复制整个目录。

我们唯一能想到的就是从头开始创建我们自己的文件对话框,但这很乏味。是否有任何“开箱即用”的解决方案?

【问题讨论】:

第一个猜测:创建自己的类,从 QFileDialog 派生并覆盖右键单击事件以不执行任何操作。 或者使用QWidgets:setContextMenuPolicy并将策略设置为Qt::NoContextMenu 我认为这是不切实际的,因为我正在使用 PyQt 绑定。我是否必须转到 C++ Qt 代码并对其进行编辑?我的 C++ 已经足够好,但我必须重新构建和重新包装所有内容,不是吗? 对不起-最后一条评论重合! setContextMenuPolicy 听起来很有希望 - 但大概 Ctrl+C 和 Ctrl+V 也必须被禁用。有没有类似的命令? 关于 PyQt:没有问题。只需在网上搜索教程。它在 Python 中运行良好。关于 Ctrl+V:这是一个新问题,所以请打开一个新问题,以免答案混淆。我通常建议您仔细阅读 QFileDialog 的文档,包括 List of all members, including inherited members 页面。 【参考方案1】:

QFileDialog 类已经具有此功能:

    dialog = QtGui.QFileDialog()
    dialog.setOption(QtGui.QFileDialog.ReadOnly, True)
    dialog.exec_()

不过,这似乎只适用于 Qt 的内置文件对话框。如果您使用静态函数打开 native 文件对话框,ReadOnly 选项似乎会被忽略(不过我只在 Linux 上测试过)。

【讨论】:

谢谢,@ekhumoro(再次!) - 这似乎取消了 Ctrl+C 和 Ctrl+V 以及上下文菜单(在 Windows 上,我正在处理)。【参考方案2】:

看看 qtreeview 的例子,他们展示了一个文件资源管理器,所以我认为实现一个简单的文件系统资源管理器实际上并不是一项艰巨的任务。感谢 QFileSystemModel http://doc.qt.io/qt-5/model-view-programming.html#using-models-and-views

【讨论】:

谢谢,@bobzer。我认为我会将其保留为备用计划,因为上面 ekhumoro 的回答似乎可以完成这项工作。这种方法对我来说有两个好处:1)我绝对 100% 确信对话没有留下“后门”,2)如果我自己制作对话,即使查看文件夹我也可以阻止它不希望它(例如 C:\Program Files (x86))。 @MikeSadler。我认为 Qt 已经涵盖了您的所有用例。您可以使用QFileDialog.setProxyModel 实现(2)。【参考方案3】:

根据@ekhumoro 的建议,这是我实际所做的:

from PyQt4 import QtGui
import guidata
import re

class _DirectoryFilterProxyModel(QtGui.QSortFilterProxyModel):
    """ A basic filter to be applied to the file items to be displayed.
     Based on C++ example at:
      https://***.com/questions/2101100/qfiledialog-filtering-folders. """

    def __init__(self, ignore_directories=[], *args, **kw):
        """ Constructor
        :param ignore_directories: A list of directories to exclude.  These
        can be regular expressions or straight names. """
        QtGui.QSortFilterProxyModel.__init__(self, *args, **kw)
        self.ignore_directories = ignore_directories

    def filterAcceptsRow(self, sourceRow, sourceParent):
        fileModel = self.sourceModel()
        index0 = fileModel.index(sourceRow, 0, sourceParent)

        if fileModel:
            if fileModel.isDir(index0):
                for directory in self.ignore_directories:
                    if re.match(directory, fileModel.fileName(index0)):
                        return False
                return True
            else:    # For files
                return True
        else:
            return False

并实例化:

app = guidata.qapplication()
dialog = QtGui.QFileDialog()
proxyModel = _DirectoryFilterProxyModel(ignore_directories=["Program Files", "Program Files (x86)", "Windows"])
dialog.setProxyModel(proxyModel)
dialog.setOption(QtGui.QFileDialog.ReadOnly, True)
dialog.setOption(QtGui.QFileDialog.HideNameFilterDetails, True)
dialog.exec_()

感谢qfiledialog - Filtering Folders? 页面上的@serge_gubenko 和@Gayan 提供了C++ 实现,我从中派生了上述内容。

【讨论】:

以上是关于防止 QFileDialog 中的文件操作,例如复制、查看、删除等的主要内容,如果未能解决你的问题,请参考以下文章

PyQt - QFileDialog - 直接浏览到文件夹?

PyQt4文件对话框QFileDialog

通过 QFileDialog 下载/保存图像

文件操作QFile和QDataStream

QFileDialog:强制文件名

QFileDialog : 获取文件名