【问题标题】:Choose Directory to create directory in PyQt5选择目录在 PyQt5 中创建目录
【发布时间】:2020-10-15 00:10:36
【问题描述】:

我正在 PyQt5 上创建 Save As... 功能。

该函数应该打开一个文件对话框,并让用户指定他们想要的目录。

以 Steam 等某些应用程序为例。当你保存 Steam 时,他们会让你选择一个目录来保存它。

用户输入:D:// 但随后他们将为用户创建 D://Steam/。此 D://Steam/ 文件夹的名称是默认名称,可以更改为用户想要的任何名称,例如:D://asdfgh/,所有内容都将下载到那里。

您可以认为该功能与 Microsoft Word 中的“另存为...”功能相同,但它不是 Word 文档,而是目录。

这是我当前的代码

saveLocation = QFileDialog.getExistingDirectory(None, "Save As...", os.getenv('HOME'))
    if saveLocation:
        currentSaveLocation = saveLocation
        fromDirectory = Main.tempPath
        toDirectory = saveLocation
        copy_tree(fromDirectory, toDirectory)

我无法将文件保存到指定目录中。

【问题讨论】:

  • 你的问题不是很清楚。使用getExistingDirectory,您将获得一个现有 路径,您是否希望用户能够选择一个“目标”目录,无论它是否存在?
  • @musicamante 是的,我希望用户能够选择一个目标目录,无论它是否存在。目录的深度应该只是当前目录的+1,例如C://newdir是可以接受的,但C://new/dir是不可接受的(假设C盘中不存在new)

标签: python-3.x pyqt dialog pyqt5


【解决方案1】:

为了获得一个可能还不存在的路径,使用 QFileDialog 的静态方法不是一个可行的解决方案。此外,我们不能使用本机 OS 文件对话框,因为与静态方法一样,它们无法提供足够的控制。

我们需要做一些小“黑客”,考虑以下几个方面:

  • 如果对话框设置为Directory fileMode,写入不存在的路径会禁用“打开”按钮;
  • 即使按钮被禁用,当在不存在路径的行编辑中按Return时,对话框仍然会抱怨不存在路径;

因此,必须采取这些预防措施:

  • 使用非原生文件对话框,以便我们可以访问子小部件;
  • 获取“打开”按钮,以便我们在需要时手动启用它;
  • 获取对话框的行编辑并手动在路径文本更改并且我们检测到有效路径时启用按钮;
  • 覆盖对话框的accept() 方法以忽略警告,并使用基类QDialog.accept() 方法;
class Test(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QHBoxLayout(self)
        self.pathEdit = QtWidgets.QLineEdit(placeholderText='Select path...')
        self.button = QtWidgets.QToolButton(text='...')
        layout.addWidget(self.pathEdit)
        layout.addWidget(self.button)
        self.button.clicked.connect(self.selectTarget)

    def selectTarget(self):
        dialog = QtWidgets.QFileDialog(self)

        if self.pathEdit.text():
            dialog.setDirectory(self.pathEdit.text())

        dialog.setFileMode(dialog.Directory)

        # we cannot use the native dialog, because we need control over the UI
        options = dialog.Options(dialog.DontUseNativeDialog | dialog.ShowDirsOnly)
        dialog.setOptions(options)

        def checkLineEdit(path):
            if not path:
                return
            if path.endswith(QtCore.QDir.separator()):
                return checkLineEdit(path.rstrip(QtCore.QDir.separator()))
            path = QtCore.QFileInfo(path)
            if path.exists() or QtCore.QFileInfo(path.absolutePath()).exists():
                button.setEnabled(True)
                return True

        # get the "Open" button in the dialog
        button = dialog.findChild(QtWidgets.QDialogButtonBox).button(
            QtWidgets.QDialogButtonBox.Open)

        # get the line edit used for the path
        lineEdit = dialog.findChild(QtWidgets.QLineEdit)
        lineEdit.textChanged.connect(checkLineEdit)

        # override the existing accept() method, otherwise selectedFiles() will 
        # complain about selecting a non existing path
        def accept():
            if checkLineEdit(lineEdit.text()):
                # if the path is acceptable, call the base accept() implementation
                QtWidgets.QDialog.accept(dialog)
        dialog.accept = accept

        if dialog.exec_() and dialog.selectedFiles():
            path = QtCore.QFileInfo(dialog.selectedFiles()[0]).absoluteFilePath()
            self.pathEdit.setText(path)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Test()
    w.show()
    sys.exit(app.exec_())

【讨论】:

  • 这是一个很好的尝试......但不幸的是,像这样替换 accept 方法有一个致命的缺陷,至少在我的机器上(W10):如果,当你输入几个字母数字字符时导致对话框的“目录”框中出现下拉菜单(因为一个或多个子目录的名称以这些字符开头),然后“选择”,不幸的是,即使对话框消失,下拉菜单仍然可见.一种解决方法是使用对话框中的“创建文件夹”图标创建目录,然后在创建后使用“选择”选择它。
  • @mikerodent 猴子补丁可能在某些情况下会产生一些问题(因此,子类化 QFileDialog 应该更合适)。下拉菜单可能是一个不相关的平台错误(你确定你 使用本机对话框,顺便说一句?),但它不应该发生,因为这正是 QFileDialog::accept()实际上确实如此。 正确的 解决方法是检查fileNameEdit 上的完成弹出窗口(并且还使用子类进行更多调试)。
  • 是的,我有点困惑,因为 1)我正在使用 DontUseNativeDialog 和 2)即使是 accept 方法的最基本替换也会导致这个“幽灵”下拉菜单保留.顺便说一句,我更喜欢pathlibos 方法来查找目录是否存在:似乎即使输入击键也会触发True 对涉及QFileInfo 的测试的响应。
猜你喜欢
  • 2017-11-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
相关资源
最近更新 更多