python-3.x - 选择目录在 PyQt5 中创建目录
问题描述
我正在 PyQt5 上创建一个 Save As... 函数。
该函数应该打开一个文件对话框,并让用户指定他们想要的目录。
以 Steam 等某些应用程序为例。当您保存 Steam 时,他们让您选择一个目录来保存它。
用户输入:D:// 但随后他们将为用户创建 D://Steam/。这个 D://Steam/ 文件夹的名称是默认名称,可以更改为用户想要的任何名称。例如:D://asdfgh/,所有内容都将下载到那里。
您可以认为该功能与 Microsoft Word 中的 Save As... 功能相同,但它不是 Word 文档,而是一个目录。
这是我当前的代码
saveLocation = QFileDialog.getExistingDirectory(None, "Save As...", os.getenv('HOME'))
if saveLocation:
currentSaveLocation = saveLocation
fromDirectory = Main.tempPath
toDirectory = saveLocation
copy_tree(fromDirectory, toDirectory)
我无法将文件保存到命名目录中。
解决方案
为了获得一个可能还不存在的路径,使用 QFileDialog 的静态方法不是一个可行的解决方案。此外,我们不能使用本机操作系统文件对话框,因为与静态方法一样,它们没有提供足够的控制。
我们需要做一些小“黑客”,考虑以下几个方面:
- 如果对话框设置为
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_())
推荐阅读
- web-component - 将一些外部 js 导入 Stenciljs Web 组件时出现问题
- javascript - 展开/折叠菜单根本不起作用
- java - NoSuchElementException 是 ResourceNotFoundException 的好选择吗?
- amazon-web-services - 直接从本地机器连接 AWS Cloud HSM
- jenkins - 如何使用 JENKINS 将代码从 gitlab 推送到从节点
- python - 使用假 mongoDB 进行 pytest 测试
- javascript - jQuery动态函数调用
- ios - XML 错误:未引用的属性值
- c# - 动态属性的名称已被用作开放类型的声明属性名称
- excel - 如何在Excel中提取不包含字符串“None”的值?