在我的 Python GUI(PyQt/PySide)应用程序中,我使用
QFileDialog
让用户选择 ONLY 一个目录,以便应用程序将在该目录中保存多个文件。该目录可以是现有的,也可以是不存在的。如果该目录不存在,我的应用程序将通过 os.makedirs(dir)
为用户创建目录
所以最初,我用这个来打开
QFileDialog
:
dir = QFileDialog.getExistingDirectory(self, "Please pick a directory...", path)
这将限制用户只能选择目录而不是文件。但是,这不允许用户选择不存在的目录。所以我不得不把它改成这样:
dir, _filter = QFileDialog.getSaveFileName(self, "Please pick a directory...", path, "Directory", "", QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
这样,我允许用户“保存”一个新目录。但是,这不允许用户选择现有目录。 (另外,如果我希望用户只看到目录,我不确定上面的过滤器是否正确)
通过坚持
QFileDialog
的静态函数,有没有办法让我允许用户选择一个可以存在或不存在的目录?
如果我必须进入非静态函数路径才能实现这一点,我可能需要更多帮助,因为我没有使用
QFileDialog
的非静态函数的经验。欢迎一些示例代码,因为我不知道如何设置尽可能接近本机文件对话框的 QFileDialog
。
这无法通过静态函数实现,因为它们是仅提供标准和常见行为的辅助函数。
由于它也是一种自定义行为,因此只能使用非本机对话框来实现:虽然某些系统可能提供一种“选择”不存在目录的方法,但目录对话框通常不希望这样做。
您必须使用 QFileDialog 子类并更改其一些行为:
为了实现第一个目标,您需要访问对话框的两个小部件:路径字段和选择按钮。
幸运的是,QFileDialog 是使用标准设计器 UI 构建的,每个小部件都有自己的
objectName
,允许我们使用 findChild()
: 访问它们
fileNameEdit
;Save
按钮;然后,我们将
textChanged
信号连接到一个自定义函数,该函数检查当前文本是否引用现有目录或不存在的路径;请注意,QFileDialog 已经将该信号连接到内部函数,允许选择空路径,指示当前可见的目录,因此我们只需要在按钮先前被禁用的情况下进行上述检查。
最后,我们需要重写对话框的
accept()
函数。以类似的方式,如果行编辑中没有输入路径,我们调用默认行为,否则我们检查它是否是目录或路径不存在。
class SelectDirDialog(QFileDialog):
def __init__(self, parent, caption='', path=''):
super().__init__(parent)
# DontUseNativeDialog must be set before anything else
self.setOptions(self.DontUseNativeDialog)
# the following order is important: AcceptSave automatically changes
# the title to "Save as" (or its translation), while we need the
# possible default for the AcceptOpen in Directory mode
self.setFileMode(self.Directory)
title = caption or self.windowTitle()
self.setAcceptMode(self.AcceptSave)
self.setWindowTitle(title)
self.setDirectory(path or QDir.currentPath())
self.fileNameEdit = self.findChild(QLineEdit, 'fileNameEdit')
self.fileNameEdit.textChanged.connect(self.checkOkButton)
self.okButton = self.findChild(QDialogButtonBox).button(
QDialogButtonBox.Save)
def accept(self):
files = self.selectedFiles()
if not files:
super().accept()
return
info = QFileInfo(files[0])
if info.isDir() or not info.exists():
QDialog.accept(self)
def checkOkButton(self):
if self.okButton.isEnabled():
return
info = QFileInfo(self.fileNameEdit.text())
self.okButton.setEnabled(info.isDir() or not info.exists())
def selectedPath(self):
files = self.selectedFiles()
return files[0] if files else ''
...
dlg = SelectDirDialog(self)
if dlg.exec():
print(dlg.selectedPath())