Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Message Box X Button Works like the Cancel Button Of the Box



  • I am facing some difficulty understanding how the functionality of the QMessage box is working. Here I have created a Simple Dialog box with a push button.

    1.JPG

    Here on clicking that push button. It will show a MessageBox.

    2.JPG

    Below I have attached the code for the QMessageBox.

    
    void dialog::on_pushButton_clicked()
    {
        QMessageBox box;
        box.setText("Choose An Option");
        QPushButton *pDiscardChangesBtn = box.addButton("Discard Changes", QMessageBox::RejectRole);
        QPushButton *pSaveChangesBtn = box.addButton("Save Changes", QMessageBox::AcceptRole);
    
        box.setDefaultButton(pSaveChangesBtn);
        box.exec();
    
        if(box.clickedButton() == pSaveChangesBtn) {
            qInfo() << "Save Changes Button Clicked";
        }
        else if(box.clickedButton() == pDiscardChangesBtn) {
            qInfo() << "Discard Changes Button clicked";
        }
        else
        {
            qInfo() << "Closed";
        }
    
    
    }
    

    here I have attached the output of the terminal.

    3.JPG

    I got the above output by first selecting "Save Changes" btn, then "Discard Changes" btn, the X button of the MessageBox Window.

    Here I have noticed that on clicking "Discard Changes" btn, X button of the windows same block of code (else if block) is getting executed.

    My doubt is

    1. why is this happening? Internally are they same or calling same method?
    2. How can I get the code in the else block get executed when clicked on X button?


  • @Abhi_Varma

    1. Internally QMessageBox will try to find an "escape" button from all buttons to set as the clicked button when "Escape" key is pressed or X is clicked, QMessageBox::RejectRole is one of the case to be chosen.
    2. If there is no such button, the X will be disabled.

    So if you don't want the discard button and X to act the same, just don't set it's role to QMessageBox::RejectRole.
    QMessageBox::DestructiveRole is more suitable for that case.

    You can also use StandardButtons like

    QMessageBox box;
    box.setText("Choose An Option");
    box.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); //I add cancel to make X enabled
    box.setDefaultButton(QMessageBox::Save);
    int result = box.exec();
    if(result == QMessageBox::Save) {
        qInfo() << "Save Button Clicked";
    }
    else if(result == QMessageBox::Discard) {
        qInfo() << "Discard Button clicked";
    }
    else
    {
        qInfo() << "Cancelled";
    }
    

  • Lifetime Qt Champion

    What should happen else? The dialog was discarded by clicking on the 'X'. I don't see why another (spurious) return value should be returned in this case.



  • @Christian-Ehrlicher Then the having the "Discard Changes" button is of no use when it does the same thing. What I want is on clicking the "X" button I need it to run the else part. Is there a way?

    The scenario I'm thinking. I have a properties page of a device, the user after filling it when the user clicks "OK". This Message Box should appear. On clicking "Save Changes" internally a saveProperties() will be triggered, It will do its thing and it will also close the properties dialog. Similarly, On clicking the "Discard Changes" Button it will call discardChanges() is triggered it does its thing and closes the properties dialog, but on clicking the "X" button only the Message Box should be closed and the properties dialog should be remained opened so that the user can continue editing the device properties.

    But from the simple example, I gave. if it's implemented for the above scenario then on clicking the "X" button it will call the discardChanges() and close the properties dialog.


  • Lifetime Qt Champion

    Then I would expect a third button for this.



  • @Abhi_Varma

    1. Internally QMessageBox will try to find an "escape" button from all buttons to set as the clicked button when "Escape" key is pressed or X is clicked, QMessageBox::RejectRole is one of the case to be chosen.
    2. If there is no such button, the X will be disabled.

    So if you don't want the discard button and X to act the same, just don't set it's role to QMessageBox::RejectRole.
    QMessageBox::DestructiveRole is more suitable for that case.

    You can also use StandardButtons like

    QMessageBox box;
    box.setText("Choose An Option");
    box.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); //I add cancel to make X enabled
    box.setDefaultButton(QMessageBox::Save);
    int result = box.exec();
    if(result == QMessageBox::Save) {
        qInfo() << "Save Button Clicked";
    }
    else if(result == QMessageBox::Discard) {
        qInfo() << "Discard Button clicked";
    }
    else
    {
        qInfo() << "Cancelled";
    }
    


  • This post is deleted!


  • @Bonnie Okay this looks interesting.... so can I hide the cancel button from the user while making X button stay active



  • @Abhi_Varma
    Wow, I would never think of that, but yes you can...
    I've tried

    box.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 
    box.button(QMessageBox::Cancel)->hide();
    

    or in your orignal code

    QPushButton *pDiscardChangesBtn = box.addButton("Discard Changes", QMessageBox::DestructiveRole);
    QPushButton *pSaveChangesBtn = box.addButton("Save Changes", QMessageBox::AcceptRole);
    QPushButton *pCancelBtn = box.addButton(QMessageBox::Cancel);
    pCancelBtn->hide();
    

    It can do the trick. :)



  • @Bonnie thanks for the quick response.... by the way is it a gud practice to do it this way?



  • @Abhi_Varma
    Well, it is not a normal way since Qt intentionally disable X button when there's no escape button.
    So this is kind of a cheat way.
    Also there's no guarantee that it will always work as expected in all future Qt versions.
    I would keep the cancel button if I don't have to hide it.



  • @Bonnie thank you so much :)



  • @Bonnie is there any other way to implement this?



  • @Abhi_Varma
    What do you mean? To have the X button enabled without adding and hiding a cancel/close button?
    You can, for example, write your own dialog instead of using QMessageBox and handle everything by yourself, but I think there's no need to do that.
    I would say hiding the button is already the best solution in my opinion...
    If you really need the button invisible, just do it.
    I would also cheat / try to change Qt's behavior in my code if I have to.


Log in to reply