0

I would like to add a QCheckBox to a QFileDialog. I would like to use the static method QFileDialog.getSaveFileName() to show the dialog.

I have found several similar questions, all in c++:

  1. How to add checkbox to QFileDialog window in QT3?
  2. Adding a widget in QFileDialog
  3. https://www.qtcentre.org/threads/42858-Creating-a-Custom-FileOpen-Dialog
  4. https://forum.qt.io/topic/103964/add-checkbox-to-qfiledialog/7

I did my best to translate these discussions to python, but have not gotten to the solution yet. My code runs, but the checkbox does not show up, even when I use QFileDialog.DontUseNativeDialog.

This is how I am subclassing QFileDialog:

from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QCheckBox

class ChkBxFileDialog(QFileDialog):
    def __init__(self, chkBxTitle=""):
        super().__init__()
        self.setOption(QFileDialog.DontUseNativeDialog)
        chkBx = QCheckBox(chkBxTitle)
        self.layout().addWidget(chkBx)
    #end __init__
#end ChkBxFileDialog

I have run this in two ways.

Option 1 (with extra QFileDialog.DontUseNativeDialog):

import sys    
from PyQt5.QtWidgets import QApplication
if __name__ == "__main__":
        app = QApplication(sys.argv)
        fileDialog = ChkBxFileDialog(chkBxTitle="Chkbx")
        fileName = fileDialog.getSaveFileName(filter='*.txt', initialFilter='*.txt',
                                              options=QFileDialog.DontUseNativeDialog)[0]
        sys.exit(app.exec_())

Option 2 (without extra QFileDialog.DontUseNativeDialog):

import sys    
from PyQt5.QtWidgets import QApplication    
if __name__ == "__main__":
        app = QApplication(sys.argv)
        fileDialog = ChkBxFileDialog(chkBxTitle="Chkbx")
        fileName = fileDialog.getSaveFileName(filter='*.txt', initialFilter='*.txt')[0]
        sys.exit(app.exec_())

The checkbox doesn't show with either option. Option 1 uses different window styling. Option 2 shows the typical PyQt QFileDialog.

Does anyone know what I am missing?

2 Answers2

1

The problem is that getSaveFileName is a static method so they do not inherit from ChkBxFileDialog and therefore do not have the custom behavior.

There are 2 options:

  • Don't use getSaveFileName but implement the logic using QFileDialog directly:

    import sys
    
    from PyQt5.QtWidgets import QApplication, QCheckBox, QDialog, QFileDialog
    
    
    class ChkBxFileDialog(QFileDialog):
        def __init__(self, chkBxTitle="", filter="*.txt"):
            super().__init__(filter=filter)
            self.setSupportedSchemes(["file"])
            self.setOption(QFileDialog.DontUseNativeDialog)
            self.setAcceptMode(QFileDialog.AcceptSave)
            self.selectNameFilter("*.txt")
            chkBx = QCheckBox(chkBxTitle)
            self.layout().addWidget(chkBx)
    
    
    def main():
        app = QApplication(sys.argv)
        dialog = ChkBxFileDialog()
        if dialog.exec_() == QDialog.Accepted:
            filename = dialog.selectedUrls()[0].toLocalFile()
            print(filename)
    
    
    if __name__ == "__main__":
        main()
    
  • Use some trick to get the QFileDialog instance, such as getting all the topLevels and verifying that it is a QFileDialog.

    import sys
    from functools import partial
    
    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QApplication, QCheckBox, QDialog, QFileDialog
    
    
    def add_checkbox(chkBxTitle):
        for tl in QApplication.topLevelWidgets():
            if isinstance(tl, QFileDialog):
                tl.setOption(QFileDialog.DontUseNativeDialog)
                chkBx = QCheckBox(chkBxTitle)
                tl.layout().addWidget(chkBx)
    
    
    def main():
        app = QApplication(sys.argv)
    
        QTimer.singleShot(1000, partial(add_checkbox, ""))
        fileName, _ = QFileDialog.getSaveFileName(
            filter="*.txt", initialFilter="*.txt", options=QFileDialog.DontUseNativeDialog
        )
    
    
    if __name__ == "__main__":
        main()
    
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • 1
    @user12751192 My answer is not different from the other but shows a possible implementation and adds another option. Note: Here we do not compete for the best answer but we give different answers or complementary answers. Please review the [tour] – eyllanesc Jul 13 '21 at 17:56
0

I would like to use the static method QFileDialog.getSaveFileName() to show the dialog

That's not possible. The static method as is defined in the C++ code knows nothing about your derived class, so it will create an instance of the base class, which doesn't contain your modifications. You have to explicitly instantiate your derived class, call exec() on the instance, check the return code and possibly call its selectedFiles() method to see what files were selected.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299