一、模態對話框
模態對話框:阻塞同一應用程序中其它可視窗口輸入的對話框。啟動模態對話框時,例如彈出對話框強制用戶從其他正在進行的業務中聚焦到當前對話框,除了該對話框整個應用程序窗口都無法接受用戶響應。只有關閉和退出該模態界面,才可以訪問本應用程序的其他界面和功能。
顯示模態對話框最常見的方法是調用其 exec() 函數,當用戶關閉對話框,exec() 將提供一個有用的返回值,並且這時流程控制繼續從調用 exec() 的地方進行。通常情況下,要獲得對話框關閉並返回相應的值,我們連接默認按鈕,例如:”確定”按鈕連接到 accept() 槽,”取消”按鈕連接到 reject() 槽。另外我們也可以連接 done() 槽,傳遞給它 Accepted 或 Rejected。
示例代碼1:
Widget *pWidget = new Widget();
pWidget->setWindowTitle(QStringLiteral("主界面"));
pWidget->show();
CustomDialog *pDialog = new CustomDialog(pWidget);
pDialog->setWindowTitle(QStringLiteral("模態對話框"));
// 關鍵代碼
pDialog->exec();
// 或者
//pDialog->setModal(true);
//pDialog->show();
// 關閉模態對話框以后才會執行下面的代碼
pWidget->setWindowTitle(QStringLiteral("主界面-模式對話框"));
qDebug() << QStringLiteral("關閉模態對話框以后,可以繼續向下執行");
示例代碼2:
我們可以通過調用 accept() 或者是 reject() 函數來是使得 exec() 函數結束代碼如下:
//可以在之前的代碼的快要結束的額時候調用accept();然后在主函數中
login *user_login=new login;//login是繼承dialog的類
int res = user_login->exec();
if (res == QDialog::Accepted)
{
delete user_login;
}
二、非模態對話框
非模態對話框:和同一個程序中其它窗口操作無關的對話框。與模態對話框相反,允許用戶同時與應用程序的主窗口和對話框進行交互,調用 show() 來顯示非模式對話框,並立即將控制返回給調用者。
示例代碼:
Widget *pWidget = new Widget();
pWidget->setWindowTitle(QStringLiteral("主界面"));
pWidget->show();
CustomDialog *pDialog = new CustomDialog(pWidget);
pDialog->setWindowTitle(QStringLiteral("非模式對話框"));
// 關鍵代碼
pDialog->show();
// 下面的代碼會立即運行
pWidget->setWindowTitle(QStringLiteral("主界面-非模式對話框"));
qDebug() << QStringLiteral("立即運行");
-
主界面不會被阻塞,可以進行點擊、拖動等任何操作。
-
show() 之后的代碼會立即執行。
三、半模態對話框
半模態對話框:介於二者之間,凍結窗口界面,但其他應用繼續執行響應。調用 setModal(true) 或者 setWindowModality(Qt::WindowModal),然后 show()。有別於 show() 立即返回給控制調用者。
Widget *pWidget = new Widget();
pWidget->setWindowTitle(QStringLiteral("主界面"));
pWidget->show();
CustomDialog *pDialog = new CustomDialog(pWidget);
pDialog->setWindowTitle(QStringLiteral("半模式對話框"));
// 關鍵代碼
pDialog->setModal(true);
pDialog->show();
// 下面的代碼會立即運行
pWidget->setWindowTitle(QStringLiteral("主界面-半模式對話框"));
qDebug() << QStringLiteral("立即運行");
-
主界面被阻塞,不能進行點擊、拖動等任何操作。
-
show()之后的代碼卻會立即執行。
四、擴展1:QWidget作為半模態窗口顯示
QDialog 實現模態和非模態很簡單,但是對於 QWidget 有點迷茫,QWidget 中沒有 exec(),也沒有 setModal() 方式,要實現半模態窗口只有以下兩種方法:
方法1:setWindowModality方法
Qt 中的 QWidget 對象自帶 setWindowModality(type) 方法,用以設置窗口模態類型。參數 type 可選為一下三種:
- Qt::NonModal 非模態:正常模式
- Qt::WindowModal 半模態:窗口級模態對話框,阻塞父窗口、父窗口的父窗口及兄弟窗口。
- Qt::ApplicationModal 模態:應用程序級模態對話框,阻塞整個應用程序的所有窗口。(實際上也只是半模態)
QWidget *pWidget = new QWidget();
pWidget->setWindowModality(Qt::ApplicationModal);
pWidget->show();
但是運行發現並未實現模態效果,只是實現了半模態。
方法2:setAttribute方法
設置部件(或窗口)屬性也可以:
pWidget->setAttribute(Qt::WA_ShowModal, true); // 屬性設置 true:模態 false:非模態
備注:QWidget 實際上實現不了真正的模態窗口,只能實現半模態窗口。
五、擴展2:QWidget模態對話框不模態的問題
自定義 QWidget 對話框,通過函數this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
設置了對話框的顯示設置后,會導致該對話框在模態顯示的時候如果設置了父窗口指針,會導致模態的設置無效,這時需要在該函數中加一個參數Qt::Dialog
就可以了。
PS:如果不傳父窗口的指針,模態也是有效的,只是這樣在任務欄上彈出的窗口也會有一個獨立的圖標,並且在任務管理其中會多一個任務出現,這樣感覺不是太好。設置父窗口后,任務欄和任務管理器中就都合並為一個了。
參考: