关于Qt模态窗口的设置

QWidget 模态

模态窗口会阻止其他窗口的输入型事件(如获取焦点),但是模态窗口的子窗口不会被限制。

(设置 setAttribute(Qt::WA_showModal, true); 的方式Qt4.5已废弃,略过)

目前,Qt中设置窗口模态是通过 QWidget 的 setWindowModality() 函数:

参数有三种枚举:

  • Qt::NonModal :(=0)表示该窗口不是模态窗口,不会阻止其他窗口的输入。
  • Qt::WindowModal :(=1)表示该窗口是单个窗口层次结构的模态,会阻止输入到其父窗口,所有祖父母窗口以及其父窗口和祖父母窗口的所有同级窗口。(说人话就是这个模态窗口对象树上的都被阻止了,除了自己的孩子,对象树就是这个模态框得设置 parent,不然是阻塞不了别的窗口的)
  • Qt::ApplicationModal :(=2)表示该窗口是应用程序的模态窗口,会阻止本应用所有窗口的输入。

(注意,Qt::WindowModal 的窗口你得设置 parent, 不然你也阻塞不了谁啊,毕竟他只会坑爹,遇到不认识的就唯唯诺诺) 

QDialog 模态

QDialog 是 QWidget 的派生类,不同于 QWidget 的默认无模态,QDialog 有三种情况:

  • 调用 show() 显示:此时的模态属性是根据你 setWindowModality 设置的模式来决定的。或者你可以设置 QDialog::setModal(bool model) ,为 false(默认 false)则表示 Qt::NonModal ,为 true 则表示 Qt::ApplicationModal 。
  • 调用 exec() 显示:此时会忽略你设置的模态属性,默认以 Qt::ApplicationModal 显示,阻塞整个应用的窗口交互,并且会同步等待返回值。
  • 调用 open() 显示:此时会忽略你设置的模态属性,默认以 Qt::WindowModal 显示,但是是异步处理,立即返回的。

相关源码赏析:

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

void QDialog::open()
{
    Q_D(QDialog);

    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
        setParent(parentWidget(), Qt::Sheet);
#endif
    }

    setResult(0);
    show();
}

参考

Qt 文档:https://doc.qt.io/qt-5/qt.html#WindowModality-enum

Qt 文档:https://doc.qt.io/qt-5/qdialog.html#modal-prop

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章