Tips for QDialogs

It is usual that our applications are not restricted to a single window, but that several options windows, messages, reports, data selection, results visualization, etc. occur.

One of the great decisions to be taken when designing these windows is their modality which, in plain language, says if you can continue using the rest of the application (not modal) or not (modal) while that window is open.

It is obvious that a non-modal window is much more complex to design than a modal window, since while it (the non-modal window) viva surely must continuously communicate with the application (or other non-modal windows) to keep the status of both (for example, imagine a window that allows the color adjustment of a video, or that displays information from an electrical network). In this case, the most normal is to design a QWidget, display it and use the appropriate communication mechanisms. As is deduced from the generic approach, this article is not about non-modal windows.

On the other hand, modal windows are simpler, since these communication mechanisms are better defined: they occur before the window is shown, and after closing; While the window is being displayed, it has its own life cycle (of events, in GUI language). They may occasionally have the famous “Apply” button, which implies an outward communication, but it usually does not differ from what happens when you “Accept”, saving that the window does not close.

In Qt, support for modal windows is provided by class QDialog, which, simplifying, is aQWidget with support for different modality options, where the main one is the method QDialog::exec which, in addition to displaying the dialogue, executes its own event loop, blocking the father’s loop, and can also return a return value.

QMessageBox

A basic example of modal dialogues can be found in the QMessageBox, which provide prebuilt basic dialogues, such as a question dialog:

if (QMessageBox::question(nullptr, "Title", "Yes or no?",
 QMessageBox::Yes | QMessageBox::No, // buttons
 QMessageBox::No) // default button
 == QMessageBox::Yes) {
}

There are a total of four possible message boxes:– QMessageBox::question: dialog with question icon (the default values ​​of the buttons supposedly show Yes / No with No by default, but at least until version 5.12.3 select Yes)– QMessageBox::information: dialogue with information icon– QMessageBox::warning: dialog with alert icon– QMessageBox::critical: dialog with error icon

The last three dialogs show by default an Accept button.

The message box icon (and any dialog or widget that is displayed as a window) will be, if not indicated otherwise, that of the parent. On the other hand, the title of the dialogs can be a personalized one, or the one of the application is used in case of indicating empty (thus saving copying the title or obtaining it from some common variable or from qApp->applicationName()) .

It is also possible to customize the texts of the buttons, but in this case it is already necessary to do it in several lines:

QMessageBox msg_box(QMessageBox::Question, "Poll", "What do you think about HeaderFiles.com?",
 QMessageBox::Yes | QMessageBox::No);
msg_box.setButtonText(QMessageBox::Yes, "Rules!");
msg_box.setButtonText(QMessageBox::No, "I <3 HF");
if (msg_box.exec() == QMessageBox::Yes) {
 qDebug() << "Of course";
} else {
 qDebug() << "Me too!";
}

QDialog

The most normal way to design a dialogue is to use the Qt Designer. I will not lengthen in this case, since here I will show how to do it programmatically (besides some options are not available from the graphic editor). It does not differ much from a QWidget, except perhaps for the way it is executed (the famous QDialog::exec()), and the possibility of connecting with the slots QDialog::accept and QDialog::reject corresponding, respectively, with the “OK” and “Cancel” buttons.

Qt Designer

When designing a dialog using the Qt Designer, the most normal thing is to create a class that inherits from QDialog, with a member variable of the typeUi::WhateverTheNameOfDialogIs, and in the constructor, invoke ui.setupUi(this). This mode is used when the dialogue is complex, has many controls or a complex workflow (associated models, multiple connections, etc.)

Programatically

This mode is especially useful when you don’t want to populate the micro-class project for dialogues that just consist of a couple of widgets (usually some tags) and a couple of buttons.

#include <qdialog.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qlabel.h>

bool basicDialog()
{
 QDialog dlg;
 
 auto layout = new QVBoxLayout();
 layout->addWidget(new QLabel("This is a dialog."));
 
 auto h_layout = new QHBoxLayout();
 h_layout->addStretch();
 auto ok_button = new QPushButton("OK");
 QObject::connect(ok_button, &QPushButton::clicked, &dlg, &QDialog::accept);
 h_layout->addWidget(ok_button);
 auto cancel_button = new QPushButton("Cancel");
 QObject::connect(cancel_button, &QPushButton::clicked, &dlg, &QDialog::reject);
 h_layout->addWidget(cancel_button);
 layout->addLayout(h_layout);
 
 dlg.setLayout(layout);
 
 return dlg.exec() == QDialog::Accepted;
}

This basic dialogue is fine, except for two details: that ? Button in the title bar (which is supposedly used to show help on controls, but not even Windows uses it, and when it uses it it does it quite badly ), and the fact that the dialogue can be freely resized. On this second depends on the design; Normally, a message-type dialog is fixed in size, while the option or result panels are usually resizable.

To solve this we must change the window flag (a broad example can be seen here).

  • Supress the help button:
    dlg.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
  • Disable resize:
    dlg.setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, true);

Note: _ in case of using these lines in a dialog designed in Qt Designer, make sure to put them _after the call to the setupUi, since if you do not run the risk of being overwritten by the values of the visual design.

More than two possible return values

Imagine that we have a dialogue to select an item from several possible, from a combo box. There is an option that is, within the class that manages the code, to use the [QDialog::done] method (https://doc.qt.io/qt-5/qdialog.html#done): The specified value will be the one returned by the dialog. In any case, it is recommended in these cases to use the accepted and implement an alternative method to query the return value; In this way the difference between an accepted and a canceled dialogue is better marked.

The full code of this entry is available at GitHub.