Introduction
In the Qt framework, QDialog is used to create dialog windows. It provides three main display methods: open()
, exec()
, and show()
. While all these methods can display dialogs, they differ significantly in behavior and usage scenarios. This article will analyze the QDialog source code to understand these differences in depth.
Brief Overview of QDialog Display Methods
First, let’s briefly understand these three methods:
show()
: Non-modal dialog displayopen()
: Window-modal dialog display, returns immediatelyexec()
: Modal dialog display, blocks until user closes
Analysis of show() Method
show()
is a QWidget method inherited by QDialog:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| void QWidget::show()
{
Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState(data->window_flags);
if (defaultState == Qt::WindowFullScreen)
showFullScreen();
else if (defaultState == Qt::WindowMaximized)
showMaximized();
else
setVisible(true); // Don't call showNormal() as not to clobber Qt::Window(Max/Min)imized
}
void QWidget::setVisible(bool visible)
{
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible)
return;
// Remember that setVisible was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
Q_D(QWidget);
d->setVisible(visible);
}
|
Characteristics:
- Non-modal display (by default)
- Returns immediately without blocking the calling thread
- Allows interaction with other application windows
- Doesn’t automatically create an event loop
Example usage:
1
2
3
| QDialog *dialog = new QDialog(this);
// Setup dialog content...
dialog->show();
|
Analysis of open() Method
open()
was introduced in Qt 4.5 for window-modal dialogs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| void QDialog::open()
{
Q_D(QDialog);
// Get current window modality
Qt::WindowModality modality = windowModality();
if (modality != Qt::WindowModal) {
d->resetModalityTo = modality;
d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
setWindowModality(Qt::WindowModal);
setAttribute(Qt::WA_SetWindowModality, false);
#ifdef Q_OS_MAC
// Set as sheet on macOS
setParent(parentWidget(), Qt::Sheet);
#endif
}
setResult(0);
show();
}
|
Characteristics:
- Window-modal display (blocks parent window interaction)
- Returns immediately
- Saves original modality state before setting window modality
- Asynchronous operation, suitable for signal-slot event handling
Example usage:
1
2
3
4
5
6
7
8
9
10
11
12
13
| QDialog *dialog = new QDialog(this);
// Setup dialog content...
connect(dialog, &QDialog::finished, this, &MyWidget::handleDialogResult);
dialog->open();
// Handle result in slot
MyWidget::handleDialogResult(int result)
{
if (result == QDialog::Accepted)
// Handle acceptance
else if (result == QDialog::Rejected)
// Handle rejection
}
|
Analysis of exec() Method
exec()
is the traditional method for modal dialogs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| int QDialog::exec()
{
Q_D(QDialog);
if (Q_UNLIKELY(d->eventLoop)) {
qWarning("QDialog::exec: Recursive call detected");
return -1;
}
bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_DeleteOnClose, false);
d->resetModalitySetByOpen();
bool wasShowModal = testAttribute(Qt::WA_ShowModal);
setAttribute(Qt::WA_ShowModal, true);
setResult(0);
show();
QPointer<QDialog> guard = this;
if (d->nativeDialogInUse) {
d->platformHelper()->exec();
} else {
QEventLoop eventLoop;
d->eventLoop = &eventLoop;
(void) eventLoop.exec(QEventLoop::DialogExec);
}
if (guard.isNull())
return QDialog::Rejected;
d->eventLoop = nullptr;
setAttribute(Qt::WA_ShowModal, wasShowModal);
int res = result();
if (d->nativeDialogInUse)
d->helperDone(static_cast<QDialog::DialogCode>(res), d->platformHelper());
if (deleteOnClose)
delete this;
return res;
}
|
Characteristics:
- Modal display (application-modal by default)
- Blocks calling thread until dialog closes
- Creates and executes local event loop
- Returns dialog result code (QDialog::Accepted/Rejected)
- Contains recursive call detection
- Prevents dialog deletion during display
Example usage:
1
2
3
4
5
6
7
| QDialog dialog(this);
// Setup dialog content...
if (dialog.exec() == QDialog::Accepted) {
// Handle acceptance
} else {
// Handle rejection
}
|
Best Practice Recommendations
The Qt documentation explicitly recommends using open()
over exec()
:
Note: Avoid using exec(); instead, use open(). Unlike exec(), open() is asynchronous and doesn’t spin an additional event loop. This prevents potential bugs (e.g., deleting the dialog’s parent while open via exec()). When using open(), connect to the finished() signal to handle dialog closure.
However, note that on macOS this enables sheet styling with system-default masking. If your project implements custom masking, this might cause visual conflicts.
Also be aware that exec()
has limitations when creating nested dialogs - you can’t hide DialogA to show DialogB and then restore DialogA after DialogB closes.
Conclusion
Through analyzing QDialog’s source code, we gain deep understanding of how open(), exec(), and show() work differently. This knowledge helps make informed decisions when implementing dialogs in Qt applications.