Search code examples
pythonpyqtpyqt4qfiledialog

Multiple files and folder selection in QFileDialog (Revisited)


This question already exists here, but the answer appears outdated or no longer works as of Python 2.7.

When I use this code to subclass my QFileDialog, the FileDialog class init is called, but the openClicked method is never called.

class FileDialog(QtGui.QFileDialog):
    def __init__(self, *args):
        QtGui.QFileDialog.__init__(self, *args)
        self.setOption(self.DontUseNativeDialog, True)
        self.setFileMode(self.ExistingFiles)
        btns = self.findChildren(QtGui.QPushButton)
        self.openBtn = [x for x in btns if 'open' in str(x.text()).lower()][0]
        self.openBtn.clicked.disconnect()
        self.openBtn.clicked.connect(self.openClicked)
        self.tree = self.findChild(QtGui.QTreeView)

    def openClicked(self):
        inds = self.tree.selectionModel().selectedIndexes()
        files = []
        for i in inds:
            if i.column() == 0:
                files.append(os.path.join(str(self.directory().absolutePath()),str(i.data().toString())))
        self.selectedFiles = files
        self.hide()

    def filesSelected(self):
        return self.selectedFiles

Is this the correct call for FileDialog?

mydialog = FileDialog()
filelist = mydialog.getExistingDirectory(self, "Select Stuff", "", QtGui.QFileDialog.DontConfirmOverwrite) 

Solution

  • The solution from the other question is unnecessarily complicated. All you need to do is override QFileDialog.accept(), and then you are free to implement whatever behaviour you like.

    The example below is very minimal. It doesn't do any checking of the selected files (like seeing whether they still exist), but that could easily be added if necessary.

    from PyQt4 import QtCore, QtGui
    
    class FileDialog(QtGui.QFileDialog):
        def __init__(self, *args, **kwargs):
            super(FileDialog, self).__init__(*args, **kwargs)
            self.setOption(QtGui.QFileDialog.DontUseNativeDialog, True)
            self.setFileMode(QtGui.QFileDialog.ExistingFiles)
    
        def accept(self):
            super(FileDialog, self).accept()
    
    class Window(QtGui.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.button = QtGui.QPushButton('Test', self)
            self.button.clicked.connect(self.handleButton)
            layout = QtGui.QVBoxLayout(self)
            layout.addWidget(self.button)
    
        def handleButton(self):
            dialog = FileDialog()
            if dialog.exec_() == QtGui.QDialog.Accepted:
                print(dialog.selectedFiles())
    
    if __name__ == '__main__':
    
        import sys
        app = QtGui.QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec_())