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

相关推荐
一个小坑货6 分钟前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet2710 分钟前
【Rust练习】22.HashMap
开发语言·后端·rust
古月居GYH11 分钟前
在C++上实现反射用法
java·开发语言·c++
在下不上天36 分钟前
Flume日志采集系统的部署,实现flume负载均衡,flume故障恢复
大数据·开发语言·python
陌小呆^O^1 小时前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp
I_Am_Me_1 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
重生之我是数学王子1 小时前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
Ai 编码助手1 小时前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹1 小时前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#