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. Hide/Show modal QDialog
Forum Updated to NodeBB v4.3 + New Features

Hide/Show modal QDialog

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 5 Posters 3.3k Views 2 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.
  • B Offline
    B Offline
    brkonator
    wrote on last edited by
    #1

    Hi, I need to be able to show/hide modal QDialog when a specific event occurs. I know, that calling QDialog::setVisible(false) on the modal dialog (after calling QDialog::exec()) calls the destructor.

    https://forum.qt.io/topic/104160/temporarily-hide-a-dialog-without-causing-it-s-dismiss-action-to-fire
    https://forum.qt.io/topic/58205/solved-modal-qdialog-setvisibible-false-calls-the-destructor/5

    These topics suggest:

    1. setting the application as a dialog's parent (but I need it to be the parent dialog, which is also modal)
    2. moving the dialog off-screen (kinda hackish - could cause some problems in multi-screen setup)
    3. setting its size to (0,0) (this seems like most friendly, but when I do this, after setting its size back to the original size, the modal dialog behaves like modeless)

    Here's my minimal reproducible sample - just a simple Qt desktop application created from a template in Qt Creator (using Qt 5.12.9 on macOS 10.15.5):

    Dialog::Dialog(QWidget *parent)
        : QDialog(parent)
        , ui(new Ui::Dialog)
    {
        ui->setupUi(this);
    
        QPushButton* bn_create = findChild<QPushButton*>("pushButton");
        connect(bn_create, &QPushButton::clicked, this, &Dialog::CreateNew);
    
        QPushButton* bn_showhide = findChild<QPushButton*>("pushButton_2");
        connect(bn_showhide, &QPushButton::clicked, this, &Dialog::ShowHideParent);
    }
    
    Dialog::~Dialog()
    {
        delete ui;
    }
    
    // creates a new modal dialog with the current dialog as its parent
    void Dialog::CreateNew()
    {
        Dialog new_dialog(this);
        new_dialog.exec();
    }
    
    // hides its parent if it's shown, shows its parent if its hidden
    void Dialog::ShowHideParent()
    {
        if (parentWidget())
        {
            static QSize original_size = parentWidget()->size();
            if (parentWidget()->size().isNull())
            {
                // after this, it behaves like modeless ???
                // allows me to click its buttons even thought its modal child is still active
                parentWidget()->resize(original_size);
            }
            else
            {
                parentWidget()->resize(0, 0);
            }
        }
    }
    
    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Simply don't call exec() but show().

      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
      4
      • mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi
        Besides using show() as Mr Ehrlicher suggests you can also use open
        https://doc.qt.io/qt-5/qdialog.html#open
        for dialog2

        That seems to work fine, keeping both modal. (at least on win 10)
        alt text

        test project
        https://www.dropbox.com/s/hm5cptaqu305s7w/ModalModalDialog.zip?dl=0

        1 Reply Last reply
        3
        • B Offline
          B Offline
          brkonator
          wrote on last edited by
          #4

          Thank you both for your answers! The only problem I have with this is that both solutions return immediately - I need the call to be blocking. I know, that the dialog's return value can be obtained via accept() or reject() signals, but in the app that I'm building I would prefer the blocking call. Can I achieve something like this with the show()/open()?

          mrjjM JonBJ 2 Replies Last reply
          0
          • B brkonator

            Thank you both for your answers! The only problem I have with this is that both solutions return immediately - I need the call to be blocking. I know, that the dialog's return value can be obtained via accept() or reject() signals, but in the app that I'm building I would prefer the blocking call. Can I achieve something like this with the show()/open()?

            mrjjM Offline
            mrjjM Offline
            mrjj
            Lifetime Qt Champion
            wrote on last edited by mrjj
            #5

            @brkonator
            Hi
            Im afraid not. But you can move the code you currently have after exec()
            to its own slot and hook up the finished() signal to this slot to have mostly same
            feature as blocking.
            It will not fire when hide/showing the dialog so should work as you want and
            first run the code on ok/cancel/x.

            You could use a lambda to keep code more local. like

            void DialogOne::on_pushButton_clicked()
            {
                if (!d2) {
                    d2 = new DialogTwo(this);
                    connect(d2, &QDialog::finished, this, [](int result) {
                        qDebug() << result;
                    });
                }
            
                d2->open();
            }
            
            1 Reply Last reply
            1
            • B brkonator

              Thank you both for your answers! The only problem I have with this is that both solutions return immediately - I need the call to be blocking. I know, that the dialog's return value can be obtained via accept() or reject() signals, but in the app that I'm building I would prefer the blocking call. Can I achieve something like this with the show()/open()?

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @brkonator
              I don't get it --- if you want a blocking call to a modal dialog, why would you then want to hide it? You haven't explained what behaviour you want when you do decide to hide it?

              1 Reply Last reply
              1
              • B Offline
                B Offline
                brkonator
                wrote on last edited by brkonator
                #7

                @JonB I'm working on the library that "wraps" multiple GUI frameworks - one of them is Qt. The idea behind this is that the user writes one code base using the library and it's up to the user, which of the underlying frameworks is used.

                Multiple working dialogs are already implemented using this library, but the current requirement is to display the modal dialog (D1) and if the user clicks a certain button, another modal dialog (D2) with the progress bar (updated by the background process) is displayed while the D1 gets hidden (and is shown only when the background process finishes and closes the D2). I know this may be a strange behavior but it's not up to me and I was able to solve this using other frameworks.

                So the sample code would look like this:

                // user's code using the library
                int main() 
                {
                    WrapperLib::Dialog d;
                    int return_value = d.ShowModal();
                    // do something based on the return_value
                }
                
                // this is the code inside the library
                namespace WrapperLib
                {
                    class Dialog
                    {
                    private:
                #ifdef _QT_FRAMEWORK
                        QDialog* dialog_impl_;
                #elif _OTHER_FRAMEWORK
                        OtherFrameworkDialogClass* dialog_impl_;
                #endif
                
                    public:
                        int ShowModal()
                        {
                #ifdef _QT_FRAMEWORK
                            return dialog_impl_->exec();
                #elif _OTHER_FRAMEWORK
                            return dialog_impl_->OtherFrameworkModalDialogBlockingMethod();
                #endif
                        }
                    };
                }
                
                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote on last edited by
                  #8

                  Maybe you can try to fake window modality? I am not entirely sure if this works. But, could one install an event filter on the QApplication object? This event filter could then ignore all events except for the currently active dialog (and most likely you still need to let paint events go through to other widgets).

                  BTW, I have read that you should be careful when nesting event loops. exec() will start its own event loop. Showing two modal dialogs then also nests two event loops. This might get you into trouble with Qt.

                  1 Reply Last reply
                  1

                  • Login

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