选择 Directory 在 PyQt5 中创建目录

Choose Directory to create directory in PyQt5

我正在 PyQt5 上创建另存为...功能。

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

以某些应用程序为例,例如 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)

我无法将文件保存到命名目录中。

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

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

  • 如果对话框设置为 Directory 文件模式,写入不存在的路径会禁用“打开”按钮;
  • 即使该按钮被禁用,当在具有不存在路径的行编辑中按 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_())