Qt对话框之二:模态、非模态、半模态对话框
一、模态对话框
模态对话框:阻塞同一应用程序中其它可视窗口输入的对话框。启动模态对话框时,例如弹出对话框强制用户从其他正在进行的业务中聚焦到当前对话框,除了该对话框整个应用程序窗口都无法接受用户响应。只有关闭和退出该模态界面,才可以访问本应用程序的其他界面和功能。
显示模态对话框最常见的方法是调用其 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:如果不传父窗口的指针,模态也是有效的,只是这样在任务栏上弹出的窗口也会有一个独立的图标,并且在任务管理其中会多一个任务出现,这样感觉不是太好。设置父窗口后,任务栏和任务管理器中就都合并为一个了。
参考: