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. How to get properly manage QMessageBox’s close signal
Forum Updated to NodeBB v4.3 + New Features

How to get properly manage QMessageBox’s close signal

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 4 Posters 3.1k Views 1 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.
  • L Offline
    L Offline
    LucaPolese
    wrote on last edited by LucaPolese
    #1

    Hi everyone,
    As I wrote in the title, I cannot manage the call of the close button ("X") of a QMessageBox.
    To give you a better understanding of what I mean, here is a picture of the window and the code I have written:

    82e1bca8-17b1-4dd9-bc3c-d0b7e2db6aad-image.png

    void MainWindow::closeEvent (QCloseEvent *event) {
        QMessageBox* messaggio;
        if(controller->getModificato()){
            messaggio = new QMessageBox(QMessageBox::Question, tr("QtDrive"), tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"), QMessageBox::Yes | QMessageBox::No, this);
            messaggio->setButtonText(QMessageBox::Yes, tr("Sì"));
            messaggio->setButtonText(QMessageBox::No, tr("No"));
            messaggio->setWindowFlags(messaggio->windowFlags() & ~Qt::WindowCloseButtonHint);
            int ret = messaggio->exec();
            if(ret == QMessageBox::Yes){
                salvaIlFile();
                //Se ho salvato effettivamente il file -> modificato sarà false.
                //Altrimenti modificato continua ad avere valore true
                //Se chiudessi perderei tutta l'informazione
                if(controller->getModificato()) event->ignore();
                else event->accept();
            }else if(ret == QMessageBox::No){
                event->accept();
            }else event->ignore();
        }else{
            ...
        }
    
    }
    

    As the name of the function suggests, what is written in this code should only be executed when the programme is closed.

    Only if there has been a change in the data (during the life of the program) the QMessageBox is presented to the user to ask if he wants to save these changes, otherwise the program is closed.

    In practice, what I want to understand is how to manage the button "X" (at the top right of the photo), because when I click it, the check stops at the second one (else if(ret == QMessageBox::No)), whereas it should simply make the event->ignore() call in else.


    I would also like to point out that I tried to remove the close button from the QMessageBox with the following codes, but the results were more than in vain:

    • messaggio->setWindowFlags((messaggio->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowCloseButtonHint);
    • messaggio->setWindowFlags(messaggio->windowFlags() & ~Qt::WindowCloseButtonHint);
    • messaggio->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint); as suggested here

    But nothing has changed

    (Maybe) useful information:
    Qt version: 5.15.2
    Qt Creator version: 4.15.2
    Architecture: x86_64

    1 Reply Last reply
    0
    • L LucaPolese

      @SamurayH It works fine for me too!
      I believe that at this point I will adopt this version too.

      The only thing that bothers me is that I can't handle the closing event of the QMessageBox ("X"), without adding the QMessageBox::Cancel button.
      Would you happen to know if there is an additional solution for this?

      Cobra91151C Offline
      Cobra91151C Offline
      Cobra91151
      wrote on last edited by
      #6

      @LucaPolese

      Hello!

      First of all, you can remove the QMessageBox close button by using this code: setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);

      Screenshot 1:
      2021-09-05_163708.png

      Secondly, you can handle the QMessageBox close event without QMessageBox::Cancel button by adding some bool class member variable to keep tracking the data change.
      In close event, you can check if your data has been changed or not. For example: I have created bool isDataChanged in dialog.h file. In constructor (dialog.cpp) file I initialized the boolean variable to isDataChanged = false;. When pressing on Update data button isDataChanged sets to true. Finally, you can check if isDataChanged to display the QMessageBox in the closeEvent method.

      void Dialog::closeEvent(QCloseEvent *event)
      {
          qDebug() << "closeEvent";
      
          if (isDataChanged) {
              QMessageBox *messaggio = new QMessageBox(
                          QMessageBox::Question,
                          tr("QtDrive"),
                          tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"),
                          QMessageBox::Yes | QMessageBox::No,
                          this);
              messaggio->setButtonText(QMessageBox::Yes, tr("Sì"));
              messaggio->setButtonText(QMessageBox::No, tr("No"));
              messaggio->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
              int ret = messaggio->exec();
      
              if (ret == QMessageBox::Yes) {
                  event->accept();
              } else {
                  event->ignore();
              }
      
              messaggio->deleteLater();
          }
      }
      

      Screenshot 2:
      Msgbox_close_example.gif

      bool isDataChanged is just a variable for a test case, in your case you can use the controller->getModificato() method instead. Happy coding!

      L 1 Reply Last reply
      4
      • SamurayHS Offline
        SamurayHS Offline
        SamurayH
        wrote on last edited by
        #2

        You can try adding a Cancel button, since the Close button is interpreted as a No:

        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
        

        "قال رسول الله صلى الله عليه وسلم : " أحب الناس إلى الله أنفعهم للناس

        L 1 Reply Last reply
        1
        • SamurayHS SamurayH

          You can try adding a Cancel button, since the Close button is interpreted as a No:

          QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
          
          L Offline
          L Offline
          LucaPolese
          wrote on last edited by
          #3

          @SamurayH I could indeed, but the problem remains: if I press the "X" button, this is interpreted as a "No", when it should be interpreted according to the else case, and should therefore make the event->ignore() call

          SamurayHS 1 Reply Last reply
          0
          • L LucaPolese

            @SamurayH I could indeed, but the problem remains: if I press the "X" button, this is interpreted as a "No", when it should be interpreted according to the else case, and should therefore make the event->ignore() call

            SamurayHS Offline
            SamurayHS Offline
            SamurayH
            wrote on last edited by SamurayH
            #4

            @LucaPolese Here's what I've tested and it works (Qt 5.14.2):

            void Widget::closeEvent(QCloseEvent *event)
            {
                if(! controller->getModificato())
                    return;
            
                QMessageBox messaggio(
                            QMessageBox::Question,
                            tr("QtDrive"),
                            tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"),
                            QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
                            this);
            
            
                messaggio.setButtonText(QMessageBox::Yes, tr("Sì"));
                messaggio.setButtonText(QMessageBox::No, tr("No"));
                messaggio.setWindowFlags(messaggio.windowFlags() & ~Qt::WindowCloseButtonHint);
            
                int ret = messaggio.exec();
            
                if(ret == QMessageBox::Yes) {
                    // Save settings
                    event->accept();
                }
                else if(ret == QMessageBox::No) {
                    // Close app
                    event->accept();
                }
                else {
                    // Do nothing (Cancel or Close)
                    event->ignore();
                }
            }

            "قال رسول الله صلى الله عليه وسلم : " أحب الناس إلى الله أنفعهم للناس

            L 1 Reply Last reply
            2
            • SamurayHS SamurayH

              @LucaPolese Here's what I've tested and it works (Qt 5.14.2):

              void Widget::closeEvent(QCloseEvent *event)
              {
                  if(! controller->getModificato())
                      return;
              
                  QMessageBox messaggio(
                              QMessageBox::Question,
                              tr("QtDrive"),
                              tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"),
                              QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
                              this);
              
              
                  messaggio.setButtonText(QMessageBox::Yes, tr("Sì"));
                  messaggio.setButtonText(QMessageBox::No, tr("No"));
                  messaggio.setWindowFlags(messaggio.windowFlags() & ~Qt::WindowCloseButtonHint);
              
                  int ret = messaggio.exec();
              
                  if(ret == QMessageBox::Yes) {
                      // Save settings
                      event->accept();
                  }
                  else if(ret == QMessageBox::No) {
                      // Close app
                      event->accept();
                  }
                  else {
                      // Do nothing (Cancel or Close)
                      event->ignore();
                  }
              }
              L Offline
              L Offline
              LucaPolese
              wrote on last edited by
              #5

              @SamurayH It works fine for me too!
              I believe that at this point I will adopt this version too.

              The only thing that bothers me is that I can't handle the closing event of the QMessageBox ("X"), without adding the QMessageBox::Cancel button.
              Would you happen to know if there is an additional solution for this?

              Cobra91151C 1 Reply Last reply
              0
              • L LucaPolese

                @SamurayH It works fine for me too!
                I believe that at this point I will adopt this version too.

                The only thing that bothers me is that I can't handle the closing event of the QMessageBox ("X"), without adding the QMessageBox::Cancel button.
                Would you happen to know if there is an additional solution for this?

                Cobra91151C Offline
                Cobra91151C Offline
                Cobra91151
                wrote on last edited by
                #6

                @LucaPolese

                Hello!

                First of all, you can remove the QMessageBox close button by using this code: setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);

                Screenshot 1:
                2021-09-05_163708.png

                Secondly, you can handle the QMessageBox close event without QMessageBox::Cancel button by adding some bool class member variable to keep tracking the data change.
                In close event, you can check if your data has been changed or not. For example: I have created bool isDataChanged in dialog.h file. In constructor (dialog.cpp) file I initialized the boolean variable to isDataChanged = false;. When pressing on Update data button isDataChanged sets to true. Finally, you can check if isDataChanged to display the QMessageBox in the closeEvent method.

                void Dialog::closeEvent(QCloseEvent *event)
                {
                    qDebug() << "closeEvent";
                
                    if (isDataChanged) {
                        QMessageBox *messaggio = new QMessageBox(
                                    QMessageBox::Question,
                                    tr("QtDrive"),
                                    tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"),
                                    QMessageBox::Yes | QMessageBox::No,
                                    this);
                        messaggio->setButtonText(QMessageBox::Yes, tr("Sì"));
                        messaggio->setButtonText(QMessageBox::No, tr("No"));
                        messaggio->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
                        int ret = messaggio->exec();
                
                        if (ret == QMessageBox::Yes) {
                            event->accept();
                        } else {
                            event->ignore();
                        }
                
                        messaggio->deleteLater();
                    }
                }
                

                Screenshot 2:
                Msgbox_close_example.gif

                bool isDataChanged is just a variable for a test case, in your case you can use the controller->getModificato() method instead. Happy coding!

                L 1 Reply Last reply
                4
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #7

                  @Cobra91151 one small thing to your suggestion: there's no need to allocated your message box on the heap. Just make it a local instance and it will be automatically destroyed at the end of the method.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  Cobra91151C 1 Reply Last reply
                  2
                  • Cobra91151C Cobra91151

                    @LucaPolese

                    Hello!

                    First of all, you can remove the QMessageBox close button by using this code: setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);

                    Screenshot 1:
                    2021-09-05_163708.png

                    Secondly, you can handle the QMessageBox close event without QMessageBox::Cancel button by adding some bool class member variable to keep tracking the data change.
                    In close event, you can check if your data has been changed or not. For example: I have created bool isDataChanged in dialog.h file. In constructor (dialog.cpp) file I initialized the boolean variable to isDataChanged = false;. When pressing on Update data button isDataChanged sets to true. Finally, you can check if isDataChanged to display the QMessageBox in the closeEvent method.

                    void Dialog::closeEvent(QCloseEvent *event)
                    {
                        qDebug() << "closeEvent";
                    
                        if (isDataChanged) {
                            QMessageBox *messaggio = new QMessageBox(
                                        QMessageBox::Question,
                                        tr("QtDrive"),
                                        tr("Vuoi salvare le modifiche prima di uscire dall'applicazione"),
                                        QMessageBox::Yes | QMessageBox::No,
                                        this);
                            messaggio->setButtonText(QMessageBox::Yes, tr("Sì"));
                            messaggio->setButtonText(QMessageBox::No, tr("No"));
                            messaggio->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
                            int ret = messaggio->exec();
                    
                            if (ret == QMessageBox::Yes) {
                                event->accept();
                            } else {
                                event->ignore();
                            }
                    
                            messaggio->deleteLater();
                        }
                    }
                    

                    Screenshot 2:
                    Msgbox_close_example.gif

                    bool isDataChanged is just a variable for a test case, in your case you can use the controller->getModificato() method instead. Happy coding!

                    L Offline
                    L Offline
                    LucaPolese
                    wrote on last edited by
                    #8

                    @Cobra91151 That's exactly what I was looking for
                    Thanks a lot!

                    1 Reply Last reply
                    0
                    • SGaistS SGaist

                      @Cobra91151 one small thing to your suggestion: there's no need to allocated your message box on the heap. Just make it a local instance and it will be automatically destroyed at the end of the method.

                      Cobra91151C Offline
                      Cobra91151C Offline
                      Cobra91151
                      wrote on last edited by
                      #9

                      @SGaist

                      Hello!

                      I know that. I just copied @LucaPolese code and modify it a bit. Besides, it calls messaggio->deleteLater(); at the end of the method, so no memory leak occurs. I forgot to mention it in my post above. For a personal use, I have created MsgDialog class which inherits from QMessageBox class and call it as a local instance. Using MsgDialog class I can make it stay always on top, add custom icon etc. The example below displays a simple usage of my class.

                      Code:

                      MsgDialog testDlg(this, "Title", "This is a test?", QMessageBox::Question, QMessageBox::Yes | QMessageBox::No);
                      int userRes = testDlg.exec();
                      
                      if (userRes == QMessageBox::Yes) {
                          //confirm
                      } else {
                         //decline
                      }
                      
                      SGaistS 1 Reply Last reply
                      0
                      • Cobra91151C Cobra91151

                        @SGaist

                        Hello!

                        I know that. I just copied @LucaPolese code and modify it a bit. Besides, it calls messaggio->deleteLater(); at the end of the method, so no memory leak occurs. I forgot to mention it in my post above. For a personal use, I have created MsgDialog class which inherits from QMessageBox class and call it as a local instance. Using MsgDialog class I can make it stay always on top, add custom icon etc. The example below displays a simple usage of my class.

                        Code:

                        MsgDialog testDlg(this, "Title", "This is a test?", QMessageBox::Question, QMessageBox::Yes | QMessageBox::No);
                        int userRes = testDlg.exec();
                        
                        if (userRes == QMessageBox::Yes) {
                            //confirm
                        } else {
                           //decline
                        }
                        
                        SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #10

                        @Cobra91151 No worries, I saw that you deleted the dialog at the end of the method. Just pointing out that it's an easy to forget step and that in this case it was not necessary to use the heap for that. It's also one small thing that allows for reduced heap fragmentation.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        0

                        • Login

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