如何解决在 QFileDialog 中预选多个文件
当显示“选择文件”对话框时,我想预先选择项目中已配置为该项目“一部分”的文件,以便用户可以选择新文件或 取消选择 现有(即之前选择的)文件。
This answer 建议可以进行多项选择。
对于这个 MRE,请制作 3 个文件并将它们放在合适的 ref_dir
中:
from PyQt5 import QtWidgets
import sys
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window,self).__init__()
self.button = QtWidgets.QPushButton('Test',self)
self.button.clicked.connect(self.handle_button)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
def handle_button(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.DontUseNativeDialog
ref_dir = 'D:\\temp'
files_list = ['file1.txt','file2.txt','file3.txt']
fd = QtWidgets.QFileDialog(None,'Choose project files',ref_dir,'(*.txt)')
fd.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
fd.setoptions(options)
# fd.setVisible(True)
for file in files_list:
print(f'selecting file |{file}|')
fd.selectFile(file)
string_list = fd.exec()
print(f'string list {string_list}')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
不幸的是,尽管已选择 ExistingFiles
作为文件模式,但我发现只有最后一个选择的文件具有选择权...但我希望在显示对话框时选择所有三个文件。
我尝试使用 setVisible
进行试验,以查看在显示对话框后是否可以以某种方式实现多选,但这不起作用。
解决方法
由于使用了非本地文件对话框,我们可以访问其子小部件来控制其行为。
一开始我想过使用item视图的选择模型,但这不会更新line edit,它负责检查文件是否存在并在这种情况下启用Ok按钮;考虑到这一点,显而易见的解决方案是直接更新行编辑:
.next.config.js
这种方法的唯一缺点是不发送 def handle_button(self):
# ...
existing = []
for file in files_list:
if fd.directory().exists(file):
existing.append('"{}"'.format(file))
lineEdit = fd.findChild(QtWidgets.QLineEdit,'fileNameEdit')
lineEdit.setText(' '.join(existing))
if fd.exec():
print('string list {}'.format(fd.selectedFiles()))
和 fileSelected
信号。
Musicamante 的回答非常非常有帮助,特别是表明选择实际上是通过用路径字符串填充 QLE 来触发的。
但实际上有一个致命的缺陷,当目的是我所说的:不幸的是,如果你试图取消选择目录中最终选定的文件,实际上这个名字是not然后从QLE。事实上,如果 QLE 设置为空白,这将禁用“选择”按钮。所有这一切都是设计使然:QFileDialog
的功能是要么“打开”或“保存”,而不是“修改”。
但我确实找到了一个解决方案,它涉及找到列出目录中文件的 QListView
,然后在其选择模型上使用信号。
这需要处理的另一件事是当您更改目录时会发生什么:显然,您随后希望根据在该目录中找到(或未找到)的项目文件来更新选择。事实上,我已经更改了“选择”按钮的文字,以显示“修改”是游戏的名称。
fd = QtWidgets.QFileDialog(app.get_main_window(),'Modify project files',start_directory,'(*.docx)')
fd.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
fd.setViewMode(QtWidgets.QFileDialog.List)
fd.setLabelText(QtWidgets.QFileDialog.Reject,'&Cancel')
fd.setLabelText(QtWidgets.QFileDialog.Accept,'&Modify')
fd.setOptions(options)
file_name_line_edit = fd.findChild(QtWidgets.QLineEdit,'fileNameEdit')
list_view = fd.findChild(QtWidgets.QListView,'listView')
# utility to cope with all permutations of backslashes and forward slashes in path strings:
def split_file_path_str(path_str):
dir_path_str,filename = ntpath.split(path_str)
return dir_path_str,(filename or ntpath.basename(dir_path_str))
fd.displayed_dir = None
sel_model = list_view.selectionModel()
def sel_changed():
if not fd.displayed_dir:
return
selected_file_paths_in_shown_dir = []
sel_col_0s = sel_model.selectedRows()
for sel_col_0 in sel_col_0s:
file_path_str = os.path.join(fd.displayed_dir,sel_col_0.data())
selected_file_paths_in_shown_dir.append(file_path_str)
already_included = file_path_str in self.files_list
if not already_included:
fd.project_files_in_shown_dir.append(file_path_str)
# now find if there are any project files which are now NOT selected
for project_file_path_str in fd.project_files_in_shown_dir:
if project_file_path_str not in selected_file_paths_in_shown_dir:
fd.project_files_in_shown_dir.remove(project_file_path_str)
sel_model.selectionChanged.connect(sel_changed)
def file_dlg_dir_entered(displayed_dir):
displayed_dir = os.path.normpath(displayed_dir)
# this is set to None to prevent unwanted selection processing triggered by setText(...) below
fd.displayed_dir = None
fd.project_files_in_shown_dir = []
existing = []
for file_path_str in self.files_list:
dir_path_str,filename = split_file_path_str(file_path_str)
if dir_path_str == displayed_dir:
existing.append('"{}"'.format(file_path_str))
fd.project_files_in_shown_dir.append(file_path_str)
file_name_line_edit.setText(' '.join(existing))
fd.displayed_dir = displayed_dir
fd.directoryEntered.connect(file_dlg_dir_entered)
# set the initially displayed directory...
file_dlg_dir_entered(start_directory)
if fd.exec():
# for each file,if not present in self.files_list,add to files list and make self dirty
for project_file_in_shown_dir in fd.project_files_in_shown_dir:
if project_file_in_shown_dir not in self.files_list:
self.files_list.append(project_file_in_shown_dir)
# also add to list widget...
app.get_main_window().ui.files_list.addItem(project_file_in_shown_dir)
if not self.is_dirty():
self.toggle_dirty()
# but we also have to make sure that a file has not been UNselected...
docx_files_in_start_dir = [f for f in os.listdir(fd.displayed_dir) if os.path.isfile(os.path.join(fd.displayed_dir,f)) and os.path.splitext(f)[1] == '.docx' ]
for docx_file_in_start_dir in docx_files_in_start_dir:
docx_file_path_str = os.path.join(fd.displayed_dir,docx_file_in_start_dir)
if docx_file_path_str in self.files_list and docx_file_path_str not in fd.project_files_in_shown_dir:
self.files_list.remove(docx_file_path_str)
list_widget = app.get_main_window().ui.files_list
item_for_removal = list_widget.findItems(docx_file_path_str,QtCore.Qt.MatchExactly)[0]
list_widget.takeItem(list_widget.row(item_for_removal))
if not self.is_dirty():
self.toggle_dirty()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。