java 非模态_Qt 之 模态、非模态、半模态窗口的介绍及 实现QDialog的exec()方法
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/GoForwardToStep/article/details/53667566
一、簡述
先簡單介紹一下模態(tài)與非模態(tài)對話框。
模態(tài)對話框
簡單一點(diǎn)講就是在彈出模態(tài)對話框時(shí),除了該對話框整個(gè)應(yīng)用程序窗口都無法接受用戶響應(yīng),處于等待狀態(tài),直到模態(tài)對話框被關(guān)閉。這時(shí)一般需要點(diǎn)擊對話框中的確定或者取消等按鈕關(guān)閉該對話框,程序得到對話框的返回值(即點(diǎn)擊了確定還是取消),并根據(jù)返回值進(jìn)行相應(yīng)的操作,之后將操作權(quán)返回給用戶。這個(gè)時(shí)候用戶可以點(diǎn)擊或者拖動(dòng)程序其他窗口。
說白了就相當(dāng)于阻塞同一應(yīng)用程序中其它可視窗口的輸入的對話框,用戶必須完成這個(gè)對話框中的交互操作并且關(guān)閉了它之后才能訪問應(yīng)用程序中的其它窗口。
其實(shí)模態(tài)對話框的作用就是得到用戶選擇的結(jié)果,根據(jù)結(jié)果來進(jìn)行下面的操作。
非模態(tài)對話框
又叫做無模式對話框,即彈出非模態(tài)對話框時(shí),用戶仍然可以對其他窗口進(jìn)行操作,不會(huì)因?yàn)檫@個(gè)對話框未關(guān)閉就不能操作其他窗口。
半模態(tài)對話框
半模態(tài)對話框區(qū)別于模態(tài)與非模態(tài)對話框,或者說是介于兩者之間,也就是說半模態(tài)對話框會(huì)阻塞窗口的響應(yīng),但是不會(huì)影響后續(xù)代碼的執(zhí)行。
Qt中的模態(tài)&非模態(tài)&半模態(tài)
QWidget
QWidget提供了setWindowModality()方法設(shè)置窗口半模態(tài)or非模態(tài);
Qt::NonModal The window is not modal and does not block input to other windows.
非模態(tài)對話框
Qt::WindowModal The window is modal to a single window hierarchy and blocks input to its parent window, all grandparent windows, and all siblings of its parent and grandparent windows.
窗口級模態(tài)對話框,即只會(huì)阻塞父窗口、父窗口的父窗口及兄弟窗口。(半模態(tài)對話框)
Qt::ApplicationModal The window is modal to the application and blocks input to all windows.
應(yīng)用程序級模態(tài)對話框,即會(huì)阻塞整個(gè)應(yīng)用程序的所有窗口。(半模態(tài)對話框)
Qt助手中的show()方法——非模態(tài)對話框
Qt助手中的介紹很簡單,就是顯示窗口以及他的子窗口。
Qt助手中的setWindowModality()方法
setWindowModality()方法可以設(shè)置窗口是否是模態(tài)窗口,從上圖中我們可以看到Qt::WindowModality的默認(rèn)值為Qt::NonModal,也就是非模態(tài)窗口。
所以,如果沒有設(shè)置Qt::WindowModality屬性值,我們每次用show()方法顯示出的窗口都是非模態(tài)窗口。
QDialog
我們知道QWidget是大部分 控件的父類,也就是說QWidget是控件的始祖類,處于最上層,而QDialog也繼承自QWidget。
在Qt助手中我們發(fā)現(xiàn)在QDialog除了繼承QWidget的show()方法外,多了兩個(gè)方法用來顯示窗口,分別是open() 和 exec()方法。
Qt助手中的open()方法——半模態(tài)對話框
可以看到使用open()方法顯示出的對話框?yàn)榇翱诩壞B(tài)對話框,并且立即返回,這樣open()方法后的代碼將會(huì)繼續(xù)執(zhí)行。open()方法就相當(dāng)于如下代碼。
void showWindow()
{
QWidget* pWindow = new QWidget();
QWidget* childWindow = new QWidget(pWindow);
childWindow->setWindowModality(Qt::WindowModal);
childWindow->show();
// 上面三行代碼相當(dāng)于下面兩行代碼;
//QDialog* childDialog = new QDialog(pWindow);
//childDialog->open();
// 下面的代碼可以執(zhí)行;
qDebug() << "這是一個(gè)半模態(tài)窗口";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Qt助手中的exec()方法——模態(tài)對話框
可以看到使用exec()方法顯示出的對話框?yàn)槟B(tài)對話框,同時(shí)會(huì)阻塞之前窗口的響應(yīng)直到用戶關(guān)閉這個(gè)對話框,并且返回DialogCode(包括Accepted和Rejected兩個(gè)值)結(jié)果。
看紅色劃線部分,如果沒有設(shè)置Qt::WindowModality屬性值,使用exec()方法顯示出的對話框默認(rèn)為應(yīng)用程序級模態(tài)對話框。所有使用exec()方法顯示對話框在窗口關(guān)閉前會(huì)阻塞整個(gè)程序所有窗口的響應(yīng)。同時(shí)調(diào)用exec()方法后的代碼也不會(huì)執(zhí)行直到對話框關(guān)閉才會(huì)繼續(xù)執(zhí)行。在關(guān)閉對話框后exec()方法會(huì)返回Accepted或者Rejected,一般程序根據(jù)返回不同的結(jié)果進(jìn)行相應(yīng)的操作。
那我們是否可以用以下代碼來代替QDialog中的exec()方法呢?
void showModalWindow()
{
QWidget* pWindow = new QWidget();
QWidget* childWindow = new QWidget(pWindow);
childWindow->setWindowModality(Qt::ApplicationModal);
childWindow->show();
// 下面的代碼可以執(zhí)行;
qDebug() << "這是一個(gè)模態(tài)窗口嗎?";
}
1
2
3
4
5
6
7
8
9
10
11
顯然是不可以的,這里調(diào)用完show()方法后立即返回了,并不知道用戶選擇了Accepted還是Rejected。而exec()會(huì)阻塞后面代碼的執(zhí)行,直到對話框關(guān)閉,返回結(jié)果。
下面用QDialog的exec()方法來顯示一個(gè)模態(tài)對話框。
void showModalWindow()
{
QWidget* pWindow = new QWidget();
QDialog* childDialog = new QDialog(pWindow);
int resutl = childDialog ->exec();
if (resutl == QDialog::Accepted)
{
qDebug() << "You Choose Ok";
}
else
{
qDebug() << "You Choose Cancel";
}
// 在關(guān)閉對話框之后,下面的代碼才可以執(zhí)行;
qDebug() << "這是一個(gè)模態(tài)窗口";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
模式對話框有自己的事件循環(huán)。按照我的理解,實(shí)際上 exec() 方法是先設(shè)置modal屬性為Qt::ApplicationModal,然后調(diào)用 show() 顯示對話框,最后啟用事件循環(huán)來阻止exec() 方法的結(jié)束。直到窗口關(guān)閉,得到返回結(jié)果(DialogCode),退出事件循環(huán),最后exec()方法調(diào)用結(jié)束,exec()方法后的代碼將繼續(xù)執(zhí)行。
QDialog的exec() 方法的實(shí)現(xiàn) 整體上就是按照上方所講的思路進(jìn)行實(shí)現(xiàn)的。關(guān)于exec() 方法返回的結(jié)果可以通過對界面上的按鈕綁定相應(yīng)的槽,比如確定按鈕綁定accept()槽,取消按鈕綁定reject()槽,這樣在點(diǎn)擊確定或者取消按鈕時(shí)exec()方法就會(huì)返回Accepted 或者 Rejected,可以根據(jù)返回的值做出相應(yīng)的操作。
下面就直接上代碼實(shí)現(xiàn)exec()方法。
二、代碼之路
實(shí)現(xiàn)QDialog的exec()方法
void MyDialog::init()
{
connect(ui.pButtonOk, SIGNAL(clicked()), this, SLOT(onOkClicked()));
connect(ui.pButtonCancel, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
}
int MyDialog::exec()
{
// 設(shè)置為模態(tài);
this->setWindowModality(Qt::ApplicationModal);
show();
// 使用事件循環(huán)QEventLoop ,不讓exec()方法結(jié)束,在用戶選擇確定或者取消后,關(guān)閉窗口結(jié)束事件循環(huán),并返回最后用戶選擇的結(jié)果;
// 根據(jù)返回結(jié)果得到用戶按下了確定還是取消,采取相應(yīng)的操作。從而模擬出QDialog類的exec()方法;
m_eventLoop = new QEventLoop(this);
m_eventLoop->exec();
return m_chooseResult;
}
void MyDialog::onOkClicked()
{
m_chooseResult = Accepted;
close();
}
void MyDialog::onCancelClicked()
{
m_chooseResult = Rejected;
close();
}
void MyDialog::closeEvent(QCloseEvent *event)
{
// 關(guān)閉窗口時(shí)結(jié)束事件循環(huán),在exec()方法中返回選擇結(jié)果;
if (m_eventLoop != NULL)
{
m_eventLoop->exit();
}
event->accept();
}
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
三、 Qt事件循環(huán)的一些理解(exec、eventloop)
1、事件循環(huán)一般用exec()函數(shù)開啟。QApplicaion::exec()、QMessageBox::exec()都是事件循環(huán)。其中前者又被稱為主事件循環(huán)。
事件循環(huán)首先是一個(gè)無限“循環(huán)”,程序在exec()里面無限循環(huán),能讓跟在exec()后面的代碼得不到運(yùn)行機(jī)會(huì),直至程序從exec()跳出。從exec()跳出時(shí),事件循環(huán)即被終止。QEventLoop::quit()能夠終止事件循環(huán)。
其次,之所以被稱為“事件”循環(huán),是因?yàn)樗芙邮帐录?#xff0c;并處理之。當(dāng)事件太多而不能馬上處理完的時(shí)候,待處理事件被放在一個(gè)“隊(duì)列”里,稱為“事件循環(huán)隊(duì)列”。當(dāng)事件循環(huán)處理完一個(gè)事件后,就從“事件循環(huán)隊(duì)列”中取出下一個(gè)事件處理之。當(dāng)事件循環(huán)隊(duì)列為空的時(shí)候,它和一個(gè)啥事也不做的永真循環(huán)有點(diǎn)類似,但是和永真循環(huán)不同的是,事件循環(huán)不會(huì)大量占用CPU資源。
事件循環(huán)的本質(zhì)就是以隊(duì)列的方式再次分配線程時(shí)間片。
2、事件循環(huán)是可以嵌套的,一層套一層,子層的事件循環(huán)執(zhí)行exec()的時(shí)候,父層事件循環(huán)就處于中斷狀態(tài);當(dāng)子層事件循環(huán)跳出exec()后,父層事件循環(huán)才能繼續(xù)循環(huán)下去。
另外,子層事件循環(huán)具有父層事件循環(huán)的幾乎所有功能。Qt會(huì)把事件送到當(dāng)前生效的那個(gè)事件循環(huán)隊(duì)列中去,其中包括Gui的各種事件。所以用戶在主線程中執(zhí)行各種exec()(如QMessageBox::exec(),QEventLoop::exec())的時(shí)候,雖然這些exec()打斷了main()中的QApplication::exec(),但是Gui界面仍然能夠正常響應(yīng)。
3、如果某個(gè)子事件循環(huán)仍然有效,但其父循環(huán)被強(qiáng)制跳出,此時(shí)父循環(huán)不會(huì)立即執(zhí)行跳出,而是等待子事件循環(huán)跳出后,父循環(huán)才會(huì)跳出。
摘自 http://blog.chinaunix.net/uid-27685749-id-3847998.html。
尾
關(guān)于模態(tài)、非模態(tài)、半模態(tài)窗口的定義也很好理解,其實(shí)也就是跟用戶操作過程中進(jìn)行交互的問題。
同時(shí)我們也通過簡單的代碼來模擬出了QDialog的exec()方法。有問題直接找Qt助手,在這里基本上便能找到我們需要的答案。所以說遇到一些問題不一定非要立馬到網(wǎng)上找各種資料或者到學(xué)習(xí)群中詢問問題的解決辦法,多看看幫助問題還是很有好處的。
http://www.kuqin.com/qtdocument/classes.html , 這個(gè)網(wǎng)址里提供了Qt文檔的中文翻譯 ,有需要的小伙伴可以看看。
————————————————
版權(quán)聲明:本文為CSDN博主「前行中的小豬」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/GoForwardToStep/article/details/53667566
總結(jié)
以上是生活随笔為你收集整理的java 非模态_Qt 之 模态、非模态、半模态窗口的介绍及 实现QDialog的exec()方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怒字开头的成语有哪些啊?
- 下一篇: php 抽象类 接口 区别,PHP中抽象