天天看點

QDialog 模态對話框與事件循環

QDialog 對話框

非模态

QDialog * dlg = new QDialog()
dlg->show();
           

       當然,這兒用指針(即配置設定到heap中)不是必須的。  (有疑問?或者有時發現視窗一閃而過?那麼你需要了解C、C++中變量的作用域和生存周期)。

模态

QDialog dlg;
dlg.exec();
           

       這種情況下,我們一般都是将對象配置設定上 stack 上,而不是heap上。

       當然,你喜歡用 heap,也沒問題:

Dialog * dlg = new QDialog();
dlg->exec();
delete dlg;
           

模态對話框

      前面的 show() 與 exec() 并不是模态與非模态的差別。

     想讓一個Widget成為模态,我們隻需要對其設定:

setAttribute(Qt::WA_ShowModal, true);
           

    注意:這是QWidget的成員函數 ,也就是說,QWidget可以顯示為模态或非模态!

setWindowModality

    除了直接調用setAttribute外,QWidget 提供了一個易用的函數,來設定窗體的模态。其源碼如下:

void QWidget::setWindowModality(Qt::WindowModality windowModality)
{
    data->window_modality = windowModality;
    // setModal_sys() will be called by setAttribute()
    setAttribute(Qt::WA_ShowModal, (data->window_modality != Qt::NonModal));
    setAttribute(Qt::WA_SetWindowModality, true);
}
           

     注意:該函數的參數取值:NonModal、WindowModal、ApplicationModal 分别對應預設情況下的

     QDialog::show()

     QDialog::open()

     QDialog::exec()

     如果你沒有使用QDialog::open()的需求,你可能也不需要該函數。

setModal

    除了QWidget提供的成員,QDialog 提供了 setModal 的成員函數,我們看看其代碼:

void QDialog::setModal(bool modal)
{
    setAttribute(Qt::WA_ShowModal, modal);
}
           

    不用解釋了吧?我們要顯示模态對話框,隻需要類似下面的代碼:

QDialog * dlg = new QDialog();
dlg->setAttribute(Qt::WA_ShowModal, true);
dlg->show();
           

exec()

int QDialog::exec()
{
    Q_D(QDialog);
...
    setAttribute(Qt::WA_ShowModal, true);
...
    show();
...
    QEventLoop eventLoop;
    (void) eventLoop.exec(QEventLoop::DialogExec);
...
}
           

      exec() 先設定modal屬性,而後調用 show() 顯示對話框,最後啟用事件循環

事件循環

     Qt 程式時事件驅動的,每個程式,我們需要調用 QApplication::exec() 來啟用事件循環。

int QCoreApplication::exec()
{
...
    QEventLoop eventLoop;
    int returnCode = eventLoop.exec();
...
    return returnCode;
}
           

    用前面的 QDialog::exec() 一樣,都是調用的 QEventLoop::exec()

int QEventLoop::exec(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
...
    while (!d->exit)
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
...
    return d->returnCode;
}
           

     而

bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    if (!d->threadData->eventDispatcher)
        return false;
    if (flags & DeferredDeletion)
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
    return d->threadData->eventDispatcher->processEvents(flags);
}
           

     進一步:這将調用平台相關的函數,比如在windows下

bool QGuiEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    if (!QEventDispatcherWin32::processEvents(flags))
        return false;
    if (configRequests)                        // any pending configs?
        qWinProcessConfigRequests();
    return true;
}
           

      事件循環和線程沒有必然的聯系,事件循環可以用在QThread中,而且從Qt4.4開始,QThread的run函數預設就調用了自己的事件循環。

     對與QDialog來說,當它自己的QEventLoop啟用時,主程式的 QEventLoop 當然是處于暫停狀态了。說到底,就是兩個死循環,一個在内,一個在外,隻有裡面的退出後,外邊的循環才會執行。不過由于兩個循環執行的指令是基本一樣的,都是調用并處理程式收到的各種事件,是以,可能變得不容易了解

參考:

https://www.yuque.com/docs/share/69c0ab8b-c33d-4629-8f17-f2fb5f956b27

繼續閱讀