版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接和本声明。
本文连接:https://blog.csdn.net/GoForwardToStep/article/details/53667566
1、简述
先简单介绍一下模态与非模态对话框。
模态对话框
简单一点讲就是在弹出模态对话框时,除了该对话框整个应用程序窗口都没法接受用户响应,处于等待状态,直到模态对话框被关闭。这时通常须要点击对话框中的肯定或者取消等按钮关闭该对话框,程序获得对话框的返回值(即点击了肯定仍是取消),并根据返回值进行相应的操做,以后将操做权返回给用户。这个时候用户能够点击或者拖动程序其余窗口。html
说白了就至关于阻塞同一应用程序中其它可视窗口的输入的对话框,用户必须完成这个对话框中的交互操做而且关闭了它以后才能访问应用程序中的其它窗口。windows
其实模态对话框的做用就是获得用户选择的结果,根据结果来进行下面的操做。app
非模态对话框
又叫作无模式对话框,即弹出非模态对话框时,用户仍然能够对其余窗口进行操做,不会由于这个对话框未关闭就不能操做其余窗口。函数
半模态对话框
半模态对话框区别于模态与非模态对话框,或者说是介于二者之间,也就是说半模态对话框会阻塞窗口的响应,可是不会影响后续代码的执行。oop
Qt中的模态&非模态&半模态
QWidget
QWidget提供了setWindowModality()方法设置窗口半模态or非模态;学习
Qt::NonModal The window is not modal and does not block input to other windows.
非模态对话框ui
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.
窗口级模态对话框,即只会阻塞父窗口、父窗口的父窗口及兄弟窗口。(半模态对话框)this
Qt::ApplicationModal The window is modal to the application and blocks input to all windows.
应用程序级模态对话框,即会阻塞整个应用程序的全部窗口。(半模态对话框).net
Qt助手中的show()方法——非模态对话框线程
Qt助手中的介绍很简单,就是显示窗口以及他的子窗口。
Qt助手中的setWindowModality()方法
setWindowModality()方法能够设置窗口是不是模态窗口,从上图中咱们能够看到Qt::WindowModality的默认值为Qt::NonModal,也就是非模态窗口。
因此,若是没有设置Qt::WindowModality属性值,咱们每次用show()方法显示出的窗口都是非模态窗口。
QDialog
咱们知道QWidget是大部分 控件的父类,也就是说QWidget是控件的始祖类,处于最上层,而QDialog也继承自QWidget。
在Qt助手中咱们发如今QDialog除了继承QWidget的show()方法外,多了两个方法用来显示窗口,分别是open() 和 exec()方法。
Qt助手中的open()方法——半模态对话框
能够看到使用open()方法显示出的对话框为窗口级模态对话框,而且当即返回,这样open()方法后的代码将会继续执行。open()方法就至关于以下代码。
void showWindow()
{
QWidget* pWindow = new QWidget();
QWidget* childWindow = new QWidget(pWindow);
childWindow->setWindowModality(Qt::WindowModal);
childWindow->show();
// 上面三行代码至关于下面两行代码;
//QDialog* childDialog = new QDialog(pWindow);
//childDialog->open();
// 下面的代码能够执行;
qDebug() << "这是一个半模态窗口";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Qt助手中的exec()方法——模态对话框
能够看到使用exec()方法显示出的对话框为模态对话框,同时会阻塞以前窗口的响应直到用户关闭这个对话框,而且返回DialogCode(包括Accepted和Rejected两个值)结果。
看红色划线部分,若是没有设置Qt::WindowModality属性值,使用exec()方法显示出的对话框默认为应用程序级模态对话框。全部使用exec()方法显示对话框在窗口关闭前会阻塞整个程序全部窗口的响应。同时调用exec()方法后的代码也不会执行直到对话框关闭才会继续执行。在关闭对话框后exec()方法会返回Accepted或者Rejected,通常程序根据返回不一样的结果进行相应的操做。
那咱们是否能够用如下代码来代替QDialog中的exec()方法呢?
void showModalWindow()
{
QWidget* pWindow = new QWidget();
QWidget* childWindow = new QWidget(pWindow);
childWindow->setWindowModality(Qt::ApplicationModal);
childWindow->show();
// 下面的代码能够执行;
qDebug() << "这是一个模态窗口吗?";
}
1
2
3
4
5
6
7
8
9
10
11
显然是不能够的,这里调用完show()方法后当即返回了,并不知道用户选择了Accepted仍是Rejected。而exec()会阻塞后面代码的执行,直到对话框关闭,返回结果。
下面用QDialog的exec()方法来显示一个模态对话框。
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";
}
// 在关闭对话框以后,下面的代码才能够执行;
qDebug() << "这是一个模态窗口";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
模式对话框有本身的事件循环。按照个人理解,实际上 exec() 方法是先设置modal属性为Qt::ApplicationModal,而后调用 show() 显示对话框,最后启用事件循环来阻止exec() 方法的结束。直到窗口关闭,获得返回结果(DialogCode),退出事件循环,最后exec()方法调用结束,exec()方法后的代码将继续执行。
QDialog的exec() 方法的实现 总体上就是按照上方所讲的思路进行实现的。关于exec() 方法返回的结果能够经过对界面上的按钮绑定相应的槽,好比肯定按钮绑定accept()槽,取消按钮绑定reject()槽,这样在点击肯定或者取消按钮时exec()方法就会返回Accepted 或者 Rejected,能够根据返回的值作出相应的操做。
下面就直接上代码实现exec()方法。
2、代码之路
实现QDialog的exec()方法
void MyDialog::init()
{
connect(ui.pButtonOk, SIGNAL(clicked()), this, SLOT(onOkClicked()));
connect(ui.pButtonCancel, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
}
int MyDialog::exec()
{
// 设置为模态;
this->setWindowModality(Qt::ApplicationModal);
show();
// 使用事件循环QEventLoop ,不让exec()方法结束,在用户选择肯定或者取消后,关闭窗口结束事件循环,并返回最后用户选择的结果;
// 根据返回结果获得用户按下了肯定仍是取消,采起相应的操做。从而模拟出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)
{
// 关闭窗口时结束事件循环,在exec()方法中返回选择结果;
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
3、 Qt事件循环的一些理解(exec、eventloop)
一、事件循环通常用exec()函数开启。QApplicaion::exec()、QMessageBox::exec()都是事件循环。其中前者又被称为主事件循环。
事件循环首先是一个无限“循环”,程序在exec()里面无限循环,能让跟在exec()后面的代码得不到运行机会,直至程序从exec()跳出。从exec()跳出时,事件循环即被终止。QEventLoop::quit()可以终止事件循环。
其次,之因此被称为“事件”循环,是由于它能接收事件,并处理之。当事件太多而不能立刻处理完的时候,待处理事件被放在一个“队列”里,称为“事件循环队列”。当事件循环处理完一个事件后,就从“事件循环队列”中取出下一个事件处理之。当事件循环队列为空的时候,它和一个啥事也不作的永真循环有点相似,可是和永真循环不一样的是,事件循环不会大量占用CPU资源。
事件循环的本质就是以队列的方式再次分配线程时间片。
二、事件循环是能够嵌套的,一层套一层,子层的事件循环执行exec()的时候,父层事件循环就处于中断状态;当子层事件循环跳出exec()后,父层事件循环才能继续循环下去。
另外,子层事件循环具备父层事件循环的几乎全部功能。Qt会把事件送到当前生效的那个事件循环队列中去,其中包括Gui的各类事件。因此用户在主线程中执行各类exec()(如QMessageBox::exec(),QEventLoop::exec())的时候,虽然这些exec()打断了main()中的QApplication::exec(),可是Gui界面仍然可以正常响应。
三、若是某个子事件循环仍然有效,但其父循环被强制跳出,此时父循环不会当即执行跳出,而是等待子事件循环跳出后,父循环才会跳出。
摘自 http://blog.chinaunix.net/uid-27685749-id-3847998.html。
尾
关于模态、非模态、半模态窗口的定义也很好理解,其实也就是跟用户操做过程当中进行交互的问题。
同时咱们也经过简单的代码来模拟出了QDialog的exec()方法。有问题直接找Qt助手,在这里基本上便能找到咱们须要的答案。因此说遇到一些问题不必定非要立马到网上找各类资料或者到学习群中询问问题的解决办法,多看看帮助问题仍是颇有好处的。
http://www.kuqin.com/qtdocument/classes.html , 这个网址里提供了Qt文档的中文翻译 ,有须要的小伙伴能够看看。 ———————————————— 版权声明:本文为CSDN博主「前行中的小猪」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。 原文连接:https://blog.csdn.net/GoForwardToStep/article/details/53667566