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

相关推荐
wjs202412 小时前
DOM CDATA
开发语言
Tingjct12 小时前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
猷咪12 小时前
C++基础
开发语言·c++
IT·小灰灰12 小时前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧12 小时前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q12 小时前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳013 小时前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾13 小时前
php 对接deepseek
android·开发语言·php
2601_9498683613 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计13 小时前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识