Qt模态对话框与非模态对话框

前言

在 Qt 中,模态对话框和非模态对话框是两种常见的对话框类型,它们的主要区别在于用户与应用程序的交互方式。

正文

对话框就是指QDialog嘛。

模态对话框 (Modal Dialog)

定义 : 模态对话框是指在弹出对话框期间,用户无法与应用程序的其他部分进行交互。用户必须先处理完对话框中的内容,才能返回到主窗口或其他窗口进行操作。

特点:

  • 阻止用户交互: 在对话框打开时,主窗口和其他窗口都不可操作。
  • 强制用户处理: 用户必须关闭或处理完对话框中的内容才能继续使用应用程序的其他部分。
  • 常用场景: 用于需要用户立即响应的情况,如确认对话框、警告框或要求用户输入关键信息的场景。

实现一:

  • 使用 QDialogexec() 方法显示模态对话框。
  • 例如:
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();
}

运行结果,可以看到只有对话框界面,没有主界面,主界面被堵塞了

当我把对话框页面叉掉时,看到主界面又显示了出来


实现二:

  • 使用 QDialogshow() 方法加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)

定义: 非模态对话框是在弹出对话框期间,用户仍然可以与应用程序的其他部分进行交互。用户可以在处理对话框的同时,也操作主窗口或其他窗口。

特点:

  • 不阻止用户交互: 对话框弹出后,用户可以自由地切换回主窗口或其他窗口进行操作。
  • 灵活性高: 适用于需要与应用程序其他部分并行操作的场景。
  • 常用场景: 用于辅助功能、工具面板或设置对话框等场景。

实现:

  • 使用 QDialogshow() 方法显示非模态对话框。
  • 例如:
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

相关推荐
宏基骑士8 分钟前
【java面向对象二】static(一)
java·开发语言
尘浮生18 分钟前
Java项目实战II基于Java+Spring Boot+MySQL的服装厂服装生产管理系统的设计与实现
java·开发语言·spring boot·后端·mysql·maven·intellij-idea
学步_技术27 分钟前
Python编码系列—Python建造者模式:构建复杂对象的优雅之道
开发语言·python·建造者模式
项目笔记与工具库31 分钟前
Java并发工具类详解:CountDownLatch与CyclicBarrier
java·开发语言·python
敲代码的奥豆1 小时前
C++:日期类的实现
开发语言·c++
看山还是山,看水还是。1 小时前
c#进度条实现方法
c语言·开发语言·笔记·c#
孑么1 小时前
C# 委托与事件 观察者模式
开发语言·unity·c#·游戏引擎·游戏程序
You can do more1 小时前
Qt Model/View之代理
qt
敲代码不忘补水1 小时前
Python Pickle 与 JSON 序列化详解:存储、反序列化与对比
开发语言·python·json
蜡笔小新星2 小时前
机器学习和深度学习的区别
开发语言·人工智能·经验分享·深度学习·学习·机器学习