一路跟踪源码,关键就是这两句:

int QDialog::exec()
{
    Q_D(QDialog);

    if (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 = 0;

    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;
}

void QWidget::hide()
{
    setVisible(false);
}

void QDialog::setVisible(bool visible)
{
    Q_D(QDialog);
    if (!testAttribute(Qt::WA_DontShowOnScreen) && d->canBeNativeDialog() && d->setNativeDialogVisible(visible))
        return;

    if (visible) {
        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
            return;

        QWidget::setVisible(visible);
        showExtension(d->doShowExtension);
        QWidget *fw = window()->focusWidget();
        if (!fw)
            fw = this;

        /*
          The following block is to handle a special case, and does not
          really follow propper logic in concern of autoDefault and TAB
          order. However, it's here to ease usage for the users. If a
          dialog has a default QPushButton, and first widget in the TAB
          order also is a QPushButton, then we give focus to the main
          default QPushButton. This simplifies code for the developers,
          and actually catches most cases... If not, then they simply
          have to use [widget*]->setFocus() themselves...
        */
        if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
            QWidget *first = fw;
            while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
                ;
            if (first != d->mainDef && qobject_cast<QPushButton*>(first))
                d->mainDef->setFocus();
        }
        if (!d->mainDef && isWindow()) {
            QWidget *w = fw;
            while ((w = w->nextInFocusChain()) != fw) {
                QPushButton *pb = qobject_cast<QPushButton *>(w);
                if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
                    pb->setDefault(true);
                    break;
                }
            }
        }
        if (fw && !fw->hasFocus()) {
            QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
            QApplication::sendEvent(fw, &e);
        }

#ifndef QT_NO_ACCESSIBILITY
        QAccessibleEvent event(this, QAccessible::DialogStart);
        QAccessible::updateAccessibility(&event);
#endif

    } else {
        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
            return;

#ifndef QT_NO_ACCESSIBILITY
        if (isVisible()) {
            QAccessibleEvent event(this, QAccessible::DialogEnd);
            QAccessible::updateAccessibility(&event);
        }
#endif

        // Reimplemented to exit a modal event loop when the dialog is hidden.
        QWidget::setVisible(visible);
        if (d->eventLoop)
            d->eventLoop->exit();
    }

    const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
    if (d->mainDef && isActiveWindow()
        && theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
        QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
}