前言
在 Qt 中,模态对话框和非模态对话框是两种常见的对话框类型,它们的主要区别在于用户与应用程序的交互方式。
正文
对话框就是指QDialog
嘛。
模态对话框 (Modal Dialog)
定义 : 模态对话框是指在弹出对话框期间,用户无法与应用程序的其他部分进行交互。用户必须先处理完对话框中的内容,才能返回到主窗口或其他窗口进行操作。
特点:
- 阻止用户交互: 在对话框打开时,主窗口和其他窗口都不可操作。
- 强制用户处理: 用户必须关闭或处理完对话框中的内容才能继续使用应用程序的其他部分。
- 常用场景: 用于需要用户立即响应的情况,如确认对话框、警告框或要求用户输入关键信息的场景。
实现一:
- 使用
QDialog
的exec()
方法显示模态对话框。 - 例如:
cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h" //这是我自己定义的类你们不必添加
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog dlg;
dlg.setWindowTitle("模态对话框");
dlg.exec();
Widget w;
w.setWindowTitle("主窗口");
w.show();
return a.exec();
}
运行结果,可以看到只有对话框界面,没有主界面,主界面被堵塞了
当我把对话框页面叉掉时,看到主界面又显示了出来
实现二:
- 使用
QDialog
的show()
方法加setModel()
显示模态对话框。 - 例如:
cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
//最好创建在堆上,这是不要学我new出来没有释放。
QDialog* dlg = new QDialog();
dlg->setWindowTitle("模态对话框");
dlg->setModal(true);
dlg->show();
w.setWindowTitle("主窗口");
w.show();
return a.exec();
}
可以看到这种方法主界面也生成了,因为show
方法调用完会将调用权返回给调用者吗,于是能继续执行代码,这种窗口类似于半模态,因为我控制不了主界面,除非我将模态窗口关闭
非模态对话框 (Modeless Dialog)
定义: 非模态对话框是在弹出对话框期间,用户仍然可以与应用程序的其他部分进行交互。用户可以在处理对话框的同时,也操作主窗口或其他窗口。
特点:
- 不阻止用户交互: 对话框弹出后,用户可以自由地切换回主窗口或其他窗口进行操作。
- 灵活性高: 适用于需要与应用程序其他部分并行操作的场景。
- 常用场景: 用于辅助功能、工具面板或设置对话框等场景。
实现:
- 使用
QDialog
的show()
方法显示非模态对话框。 - 例如:
cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QDialog dlg;
dlg.setWindowTitle("非模态对话框");
dlg.show();
w.setWindowTitle("主窗口");
w.show();
return a.exec();
}
可以看到这里是能操纵主界面的
扩展:QWidget作为半模态窗口显示
实现:
- 方法一:
setWindowModality
方法
Qt 中的 QWidget
对象自带 setWindowModality(type)
方法,用以设置窗口模态类型。参数 type 可选为一下三种:
Qt::NonModal
非模态:正常模式
Qt::WindowModal
半模态:窗口级模态对话框,阻塞父窗口、父窗口的父窗口及兄弟窗口。
Qt::ApplicationModal
模态:应用程序级模态对话框,阻塞整个应用程序的所有窗口。(实际上也只是半模态)
cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("QWidget实现半模态");
w.setWindowModality(Qt::ApplicationModal);
w.show();
QDialog d;
d.show();
return a.exec();
}
但是运行发现并未实现模态效果,只是实现了半模态。
- 方法二:
setAttribute
方法
cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("QWidget实现半模态");
// true:模态, false:非模态
w.setAttribute(Qt::WA_ShowModal,true);
w.show();
QDialog d;
d.show();
return a.exec();
}
pWidget->setAttribute(Qt::WA_ShowModal, true); // 属性设置 true:模态 false:非模态
注意:QWidget 实际上实现不了真正的模态窗口,只能实现半模态窗口。
自定义模态对话框不模态问题
自定义QWidget
对话框,如果通过函数
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Dialog);
设置了对话框的显示设置后,会导致该对话框在模态显示的时候如果设置了父窗口指针,会导致模态的设置无效,这时需要在该函数中加一个参数Qt::Dialog
就可以了。
cpp
//main.cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
#include "definedialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("DefineDialog模态无效");
//指定父窗口
DefineDialog dfg(&w);
//设置模态
dfg.setWindowModality(Qt::ApplicationModal);
dfg.show();
w.show();
return a.exec();
}
// DefineDialog.cpp
#include "definedialog.h"
#include "ui_definedialog.h"
DefineDialog::DefineDialog(QWidget *parent) :
QWidget(parent),
ui(new Ui::DefineDialog)
{
ui->setupUi(this);
// | Qt::Dialog
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
//将上句改成this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Dialog );可使得模态生效
}
DefineDialog::~DefineDialog()
{
delete ui;
}
PS:如果不传父窗口的指针,设置窗口状态时无论是否添加Qt::Dialog
模态都是是有效的,只是这样在任务栏上弹出的窗口也会有一个独立的图标,并且在任务管理其中会多一个任务出现,这样感觉不是太好。设置父窗口后,任务栏和任务管理器中就都合并为一个了。
cpp
//main.cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
#include "definedialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("DefineDialog模态一定有效");
DefineDialog dfg;
//设置模态
dfg.setWindowModality(Qt::ApplicationModal);
dfg.show();
w.show();
return a.exec();
}
// DefineDialog.cpp
#include "definedialog.h"
#include "ui_definedialog.h"
DefineDialog::DefineDialog(QWidget *parent) :
QWidget(parent),
ui(new Ui::DefineDialog)
{
ui->setupUi(this);
// 加不加| Qt::Dialog都可以
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
}
DefineDialog::~DefineDialog()
{
delete ui;
}
下图就是不指定父窗口时会出现
关于Qt Creater快速入门(霍亚飞,第三版,51页多窗口切换例子的解读)
代码我就不全部粘出来了,书上都有,我只写一些我认为重要的
cpp
//main.cpp
#include "widget.h"
#include <QApplication>
#include "mydialog.h"
#include "qdialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
// 创建子界面
MyDialog dialog;
// dialog.exec() == QDialog::Accepted 其实相当于两步
// 第一步 int temp = dialog.exec(); 这一步等号右边会生成一个模态对话框
// 第二步 temp == QDialog::Accepted
if (dialog.exec() == QDialog::Accepted) {
w.show();
return a.exec();
}
else return 0;
}
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "mydialog.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->btnBegin,&QPushButton::clicked,this,&Widget::showDialog);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnDialog_clicked()
{
//关闭主界面
this->close();
//创建子窗口对象
MyDialog mdlg;
// 这里mdlg.exec() == QDialog::Accepted 其实相当于两步
// 第一步 int temp = mdlg.exec(); 这一步等号右边会生成一个模态对话框
// 第二步 temp == QDialog::Accepted
if (mdlg.exec() == QDialog::Accepted) this->show();
}
void Widget::showDialog()
{
MyDialog* dlg = new MyDialog(this);
dlg->show();
}
//MyDialog.cpp
#include "mydialog.h"
#include "ui_mydialog.h"
MyDialog::MyDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::MyDialog)
{
ui->setupUi(this);
}
MyDialog::~MyDialog()
{
delete ui;
}
void MyDialog::on_btnMain_clicked()
{
// 本函数调用后会隐藏模态对话框,并返回QDialog::Accepted
accept();
}
注意创建你的MyDialog设计师类时一定要继承QDialog
运行结果
huoYafei_duochuangkouqiehuan