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

相关推荐
PieroPc2 分钟前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439693 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
Dream_Snowar4 小时前
速通Python 第三节
开发语言·python
高山我梦口香糖5 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
mahuifa5 小时前
混合开发环境---使用编程AI辅助开发Qt
人工智能·vscode·qt·qtcreator·编程ai
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
信号处理学渣5 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客5 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++