PyQt QFileDialog - 多个目录选择

4

我正在尝试创建一个QFileDialog,允许用户选择多个目录。

根据这里的讨论here和这里的faq here,但我不确定我做错了什么。我得到了一个文件对话框,但它仍然只允许我选择单个目录(文件夹)。

这是在Windows 7上运行的。

代码:

class FileDialog(QtGui.QFileDialog):
        def __init__(self, *args):
            QtGui.QFileDialog.__init__(self, *args)
            self.setOption(self.DontUseNativeDialog, True)
            self.setFileMode(self.DirectoryOnly)

            self.tree = self.findChild(QtGui.QTreeView)
            self.tree.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)

            self.list = self.findChild(QtGui.QListView)
            self.list.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    ex = FileDialog()
    ex.show()
    sys.exit(app.exec_())

编辑:

经过进一步尝试,如果我在文件对话框中选择“详细视图”,多选功能可以正常工作。然而,如果我选择“列表视图”,它就无法正常工作。有任何想法为什么吗?

1个回答

8
FAQ中的示例代码不够健壮,因为它假定对话框只有一个QListView和一个QTreeView。当有多个直接子对象时,findChild的行为是不确定的:因此,它可能只是偶然成功了。

更为健壮的解决方案是对任何模型类型为QFileSystemModel的视图重置选择模式:

for view in self.findChildren((QListView, QTreeView)):
    if isinstance(view.model(), QFileSystemModel):
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)

这里是一个简单的演示脚本:

from PyQt5 import QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.button = QtWidgets.QPushButton('Choose Directories')
        self.button.clicked.connect(self.handleChooseDirectories)
        self.listWidget = QtWidgets.QListWidget()
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.listWidget)
        layout.addWidget(self.button)

    def handleChooseDirectories(self):
        dialog = QtWidgets.QFileDialog(self)
        dialog.setWindowTitle('Choose Directories')
        dialog.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
        dialog.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
        for view in dialog.findChildren(
            (QtWidgets.QListView, QtWidgets.QTreeView)):
            if isinstance(view.model(), QtWidgets.QFileSystemModel):
                view.setSelectionMode(
                    QtWidgets.QAbstractItemView.ExtendedSelection)
        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            self.listWidget.clear()
            self.listWidget.addItems(dialog.selectedFiles())
        dialog.deleteLater()

if __name__ == '__main__':

    app = QtWidgets.QApplication(['Test'])
    window = Window()
    window.show()
    app.exec_()

1
由于我花了半小时才弄清楚,希望下一个新手能免除这个麻烦:在将此答案与示例结合使用后,您可以在 ex.show() 后使用 ex.selectedFiles() 找到所选目录。 - Frikster
1
@DirkHaupt。dialog.exec_() - ekhumoro
2
@DirkHaupt。view.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) - ekhumoro
ekhumoro或其他人:您能否考虑将评论中的解决方案集成到主答案中?这对于下一个人来说很好,他们可以看到解决方案的各个部分,也许还有一个独立的示例。 - Nav
感谢您提供的更新示例,ekhumoro。它非常出色! - Nav
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接