Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Subclassing QFileDialog
Forum Updated to NodeBB v4.3 + New Features

Subclassing QFileDialog

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 7 Posters 1.2k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • PerdrixP Online
    PerdrixP Online
    Perdrix
    wrote on last edited by Perdrix
    #1

    The MFC code that I am converting to use Qt uses a sub-class of CFileDialog to that uses CDialog::SetTemplate() function to append additional controls defined in a user resource file to the standard dialogue.

    The resulting save file dialogue looks like this:

    4dc05345-d87d-4da5-a8c1-34cb062a97d0-image.png

    This is very effective, but unfortunately I can't seem to find a way to do this using QFileDialog.

    Is there a way to achieve something similar to this in Qt?

    Thanks, David

    Pl45m4P 1 Reply Last reply
    0
    • PerdrixP Perdrix

      I find that really depressing - I so don't want to have to spin my own version of QFileDialog from the ground up.

      David

      M Offline
      M Offline
      mpergand
      wrote on last edited by mpergand
      #8

      @Perdrix

      According to the docs, I think its possible if not using the native file dialog.

      By default, a platform-native file dialog will be used if the platform has one. In that case, the widgets which would otherwise be used to construct the dialog will not be instantiated, so related accessors such as layout() and itemDelegate() will return null. You can set the DontUseNativeDialog option to ensure that the widget-based implementation will be used instead of the native dialog.

      The following add a button at the bottom.

      QFileDialog fd;
      fd.setOption(QFileDialog::DontUseNativeDialog);
      fd.layout()->addWidget(new QPushButton("Extra button"));
      
      1 Reply Last reply
      1
      • PerdrixP Perdrix

        The MFC code that I am converting to use Qt uses a sub-class of CFileDialog to that uses CDialog::SetTemplate() function to append additional controls defined in a user resource file to the standard dialogue.

        The resulting save file dialogue looks like this:

        4dc05345-d87d-4da5-a8c1-34cb062a97d0-image.png

        This is very effective, but unfortunately I can't seem to find a way to do this using QFileDialog.

        Is there a way to achieve something similar to this in Qt?

        Thanks, David

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by Pl45m4
        #2

        @Perdrix said in Subclassing QFileDialog:

        Is there a way to achieve something similar to this in Qt?

        QFileDialog inherits from QDialog.
        So you can subclass it and add your own layout with additional things you need.
        If you want to replicate the exact same as in your screenshot, there are two QGroupBox containers with check- and radio buttons... so should not be a big deal.

        Keep in mind, when you subclass QFileDialog you always get the Qt Widget "style" File Dialog and never the platform native one, which, for example, can be invoked using the static methods of QFileDialog.


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        1 Reply Last reply
        2
        • PerdrixP Online
          PerdrixP Online
          Perdrix
          wrote on last edited by Perdrix
          #3

          Some guidance on that would be very helpful. It's not clear to me how I'd override its layout and add controls. The way that QFileDialogPrivate::createWidgets() works looks like this will be very difficult without copying the entire code of (at least) that function to override the layout.

          Meantime, I'll look deeper into its source code to see whether I can work it out for myself

          Thanks, David

          1 Reply Last reply
          0
          • Christian EhrlicherC Online
            Christian EhrlicherC Online
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #4

            QFileDialog is not really meant to be overriden. Create your own dialog if you want something special.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            0
            • PerdrixP Online
              PerdrixP Online
              Perdrix
              wrote on last edited by
              #5

              I find that really depressing - I so don't want to have to spin my own version of QFileDialog from the ground up.

              David

              Pl45m4P M 2 Replies Last reply
              0
              • PerdrixP Perdrix

                I find that really depressing - I so don't want to have to spin my own version of QFileDialog from the ground up.

                David

                Pl45m4P Offline
                Pl45m4P Offline
                Pl45m4
                wrote on last edited by
                #6

                @Perdrix

                But it's the same for every other widget.
                When subclassing e.g. QAbstractButton you get the interface only... the button is "empty" and needs to be defined and customized by you. Unfortunately there's nothing such as "a little default behavior" and then add your own stuff to it.


                If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                ~E. W. Dijkstra

                1 Reply Last reply
                0
                • sbelaS Offline
                  sbelaS Offline
                  sbela
                  wrote on last edited by
                  #7

                  QFileDialog is open source. Use that as a starting point.

                  I would like!

                  1 Reply Last reply
                  1
                  • PerdrixP Perdrix

                    I find that really depressing - I so don't want to have to spin my own version of QFileDialog from the ground up.

                    David

                    M Offline
                    M Offline
                    mpergand
                    wrote on last edited by mpergand
                    #8

                    @Perdrix

                    According to the docs, I think its possible if not using the native file dialog.

                    By default, a platform-native file dialog will be used if the platform has one. In that case, the widgets which would otherwise be used to construct the dialog will not be instantiated, so related accessors such as layout() and itemDelegate() will return null. You can set the DontUseNativeDialog option to ensure that the widget-based implementation will be used instead of the native dialog.

                    The following add a button at the bottom.

                    QFileDialog fd;
                    fd.setOption(QFileDialog::DontUseNativeDialog);
                    fd.layout()->addWidget(new QPushButton("Extra button"));
                    
                    1 Reply Last reply
                    1
                    • PerdrixP Perdrix has marked this topic as solved on
                    • PerdrixP Online
                      PerdrixP Online
                      Perdrix
                      wrote on last edited by
                      #9

                      Woohoo!

                      image.png

                      SavePicture.h (part)

                      namespace DSS
                      {
                      	class SavePicture final : public QFileDialog
                      	{
                      		Q_OBJECT
                      
                      	public:
                      		SavePicture(QWidget* parent = nullptr, const QString& caption = QString(), const QString& directory = QString(), const QString& filter = QString());
                      
                      		~SavePicture() = default;
                      
                      		SavePicture(const SavePicture&) = delete;
                      		SavePicture(SavePicture&&) = delete;
                      		SavePicture& operator=(const SavePicture& rhs) = delete;
                      
                      		void retranslateUi(QWidget*);
                      
                      	private:
                      		QGroupBox* compressionGroup;
                      		QHBoxLayout* compressionLayout;
                      		QRadioButton* compressionNone;
                      		QRadioButton* compressionZIP;
                      		QRadioButton* compressionLZW;
                      
                      		QGroupBox* optionsGroup;
                      		QVBoxLayout* optionsLayout;
                      		QRadioButton* applyAdjustments;
                      		QRadioButton* embedAdjustments;
                      		QCheckBox* useRectangle;
                      
                      		QString embedText;
                      		QString noAdjustments;
                      

                      SavePicture.cpp (part)

                      namespace DSS
                      {
                      	SavePicture::SavePicture(QWidget* parent, const QString& caption, const QString& directory, const QString& filter) :
                      		QFileDialog(parent, caption, directory, filter),
                      		compressionGroup(new QGroupBox(this)),
                      		compressionLayout(new QHBoxLayout(compressionGroup)),
                      		compressionNone(new QRadioButton(compressionGroup)),
                      		compressionZIP(new QRadioButton(compressionGroup)),
                      		compressionLZW(new QRadioButton(compressionGroup)),
                      		optionsGroup(new QGroupBox(this)),
                      		optionsLayout(new QVBoxLayout(optionsGroup)),
                      		applyAdjustments(new QRadioButton(optionsGroup)),
                      		embedAdjustments(new QRadioButton(optionsGroup)),
                      		useRectangle(new QCheckBox(optionsGroup))
                      	{
                      		compressionGroup->setObjectName("compressionGroup");
                      		compressionLayout->setObjectName("compressionLayout");
                      		compressionNone->setObjectName("compressionNone");
                      		compressionZIP->setObjectName("compressionZIP");
                      		compressionLZW->setObjectName("compressionLZW");
                      
                      		optionsGroup->setObjectName("optionsGroup");
                      		optionsLayout->setObjectName("optionsLayout");
                      		applyAdjustments->setObjectName("applyAdjustments");
                      		embedAdjustments->setObjectName("embedAdjustments");
                      		useRectangle->setObjectName("useRectangle");
                      
                      		compressionGroup->setLayout(compressionLayout);
                      		compressionLayout->addWidget(compressionNone);
                      		compressionLayout->addWidget(compressionZIP);
                      		compressionLayout->addWidget(compressionLZW);
                      
                      		optionsGroup->setLayout(optionsLayout);
                      		optionsLayout->addWidget(applyAdjustments);
                      		optionsLayout->addWidget(embedAdjustments);
                      		optionsLayout->addWidget(useRectangle);
                      
                      		retranslateUi(this);
                      
                      		setOption(QFileDialog::DontUseNativeDialog);
                      
                      		QGridLayout* layout{ dynamic_cast<QGridLayout*>(this->layout()) };
                      		layout->addWidget(compressionGroup, layout->rowCount(), 0, 1, 2);
                      		layout->addWidget(optionsGroup, layout->rowCount(), 0, 1, 2);
                      	}
                      
                      	void SavePicture::retranslateUi([[maybe_unused]]QWidget* wdgt)
                      	{
                      		compressionGroup->setTitle(tr("Compression", "IDD_SAVEPICTURE"));
                      		compressionNone->setText(tr("None", "IDC_COMPRESSION_NONE"));
                      		compressionZIP->setText(tr("ZIP (Deflate)", "IDC_COMPRESSION_ZIP"));
                      		compressionLZW->setText(tr("ZIP (Deflate)", "IDC_COMPRESSION_LZW"));
                      		optionsGroup->setTitle(tr("Options", "IDD_SAVEPICTURE"));
                      		applyAdjustments->setText(tr("Apply adjustments to the saved image", "IDC_APPLIED"));
                      		embedAdjustments->setText(tr("Embed adjustments in the saved image but do not apply them", "IDC_EMBEDDED"));
                      		embedText = embedAdjustments->text();
                      		noAdjustments = tr("Do not apply adjustments to the saved image", "IDS_SAVENOADJUSTMENT");
                      		useRectangle->setText(tr("Create an image from the selected rectangle", "IDC_USERECT"));
                      	}```
                      1 Reply Last reply
                      4
                      • R Offline
                        R Offline
                        RoXus
                        wrote on last edited by
                        #10

                        This code probably works fine for saving dialogs, but (at least in my X11-environment) opening of a file does not, as the dialog closes as soon as a file is selected. But I found a solution by subclassing QFileDialog. The most important snippets of my Python-code are as follows:

                            def __init__(self, parent=None):
                                ...
                                # set custom dialog option
                                self.setOption(QFileDialog.DontUseNativeDialog)
                                # add your own widgets to the dialog
                                layg: QGridLayout = self.layout()
                                # the standard layout of QFileDialog is a QGridLayout with 4 rows and 3 columns; 
                                # so add your widgets from row 5 onwards
                                ...
                                # redirect accept signal from open button, which is a QDialogButtonBox in 
                                # row 2, column 2
                                itm_open = layg.itemAtPosition(2, 2)
                                itm_open.widget().accepted.connect(self.accept_button)      
                                self.show()
                        
                            def accept(self):
                                # override the standard accept function, which is triggered
                                # on file selection
                                logger.debug('accepted via file selection')
                                filename = self.selectedFiles()[0]
                                # I e.g. used the additional widgets to display parts of the contents 
                                # of the file; this code follows here
                                ...
                                # and IMPORTANT: do NOT call super().accept(), as this closes 
                                # the dialog immediately
                        
                            def accept_button(self):
                                # react on the click of the open button
                                logger.debug('accepted via button')
                                ...
                                # now it is time to call super().accept()
                                super().accept()
                        
                        
                        JonBJ 1 Reply Last reply
                        0
                        • R RoXus

                          This code probably works fine for saving dialogs, but (at least in my X11-environment) opening of a file does not, as the dialog closes as soon as a file is selected. But I found a solution by subclassing QFileDialog. The most important snippets of my Python-code are as follows:

                              def __init__(self, parent=None):
                                  ...
                                  # set custom dialog option
                                  self.setOption(QFileDialog.DontUseNativeDialog)
                                  # add your own widgets to the dialog
                                  layg: QGridLayout = self.layout()
                                  # the standard layout of QFileDialog is a QGridLayout with 4 rows and 3 columns; 
                                  # so add your widgets from row 5 onwards
                                  ...
                                  # redirect accept signal from open button, which is a QDialogButtonBox in 
                                  # row 2, column 2
                                  itm_open = layg.itemAtPosition(2, 2)
                                  itm_open.widget().accepted.connect(self.accept_button)      
                                  self.show()
                          
                              def accept(self):
                                  # override the standard accept function, which is triggered
                                  # on file selection
                                  logger.debug('accepted via file selection')
                                  filename = self.selectedFiles()[0]
                                  # I e.g. used the additional widgets to display parts of the contents 
                                  # of the file; this code follows here
                                  ...
                                  # and IMPORTANT: do NOT call super().accept(), as this closes 
                                  # the dialog immediately
                          
                              def accept_button(self):
                                  # react on the click of the open button
                                  logger.debug('accepted via button')
                                  ...
                                  # now it is time to call super().accept()
                                  super().accept()
                          
                          
                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #11

                          @RoXus said in Subclassing QFileDialog:

                              itm_open = layg.itemAtPosition(2, 2)
                              itm_open.widget().accepted.connect(self.accept_button)      
                          

                          Just an observation. For you or anyone else reading this, obviously this relies on the dialog having a QGridLayout and the desired button being positioned in cell (2, 2). Probably a more robust approach is to find the QDialogButtonBox, or better the actual button. From Python you can start from

                          box = self.findChild(QDialogButtonBox)
                          # or
                          buttons = self.findChildren(QPushButton)
                          

                          Look at the docs for these, you can e.g. add the objectName() if you know what it is for the button you want, or similar.

                          1 Reply Last reply
                          4

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved