【Qt学习】04:QDialog

这篇具有很好参考价值的文章主要介绍了【Qt学习】04:QDialog。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

QDialog


对话框是 GUI 程序中不可或缺的组成部分,对话框通常会是一个顶层窗口出现在程序最上层,用于实现短期任务或者简单用户交互。

Qt 中使用QDialog类实现对话框,通常会设计一个类继承QDialog。如果QDialog 的 parent 为 NULL,则该对话框会作为一个顶层窗口,否则则作为其父组件的子对话框(此时其默认出现的位置是 parent 的中心),顶层窗口与非顶层窗口的区别在于,顶层窗口在任务栏会有自己的位置,而非顶层窗口则会共享其父组件的位置。

标准对话框是 Qt 内置的一系列对话框用于简化开发,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。

Qt 的内置的标准对话框大致分为以下几类:

  • QColorDialog: 选择颜色;
  • QFileDialog: 选择文件或者目录;
  • QFontDialog: 选择字体;
  • QInputDialog: 允许用户输入一个值,并将其值返回;
  • QMessageBox: 消息对话框,模态对话框,用于显示信息、询问问题等;
  • QPageSetupDialog: 为打印机提供纸张相关的选项;
  • QPrintDialog: 打印机配置;
  • QPrintPreviewDialog:打印预览;
  • QProgressDialog: 显示操作过程。

一、自定义对话框

对话框分为模态对话框和非模态对话框,

  • 模态对话框,会阻塞同一应用程序中其它窗口的输入。模态对话框很常见,比如“打开文件”功能。你可以尝试一下记事本的打开文件,当打开文件对话框出现时,我们是不能对除此对话框之外的窗口部分进行操作的。
  • 非模态对话框相反,例如查找对话框,我们可以在显示着查找对话框的同时,继续对记事本的内容进行编辑。

Qt 支持模态对话框和非模态对话框,模态与非模态的实现:

  • 使用 QDialog::exec() 实现应用程序级别的模态对话框
  • 使用 QDialog::open() 实现窗口级别的模态对话框
  • 使用 QDialog::show() 实现非模态对话框。
1.模态对话框

Qt 有两种级别的模态对话框:

  1. 应用程序级别的模态(默认):

    当该种模态的对话框出现时,用户必须首先对对话框进行交互,直到关闭对话框,然后才能访问程序中其他的窗口。

  2. 窗口级别的模态:

    该模态仅仅阻塞与对话框关联的窗口,但是依然允许用户与程序中其它窗口交互。窗口级别的模态尤其适用于多窗口模式。

调用exec()将对话框显示出来(模态对话框),当对话框出现时用户不能与主窗口进行任何交互,直到关闭了该对话框。

QDialog dialog(this);//对象创建在栈上(匿名函数释放后 dialog对象会释放)
dialog.resize(400, 300);
dialog.setWindowTitle("modal dialog");
dialog.exec();
qDebug() << "modal dialog poped up.";
2.非模态对话框

下面将 exec() 修改为 show() 定义出非模态对话框:

QDialog dialog(this);
dialog->resize(400, 300);
dialog->setWindowTitle("modalless dialog");
dialog->show();
qDebug() << "modalless dialog poped up.";

对话框竟然一闪而过,这是因为 show() 函数不会阻塞当前线程对话框会显示出来,然后函数立即返回代码继续执行。dialog 是建立在栈上的,当show()函数返回MainWindow::open()函数结束,dialog 超出作用域被析构,因此对话框消失了。

将 dialog 改成堆上建立,就不会出现这个问题了:

QDialog *dialog = new QDialog(this);//对象创建在堆区(匿名函数释放后 dialog对象不会释放)
dialog->resize(400, 300);
dialog->setWindowTitle("modalless dialog");
dialog->show();
qDebug() << "modalless dialog poped up.";

上面的代码是有问题的dialog 存在内存泄露,dialog 使用 new 在堆上分配空间却一直没有 delete。解决方案也很简单:将 MainWindow 的指针赋给 dialog 即可,利用对象树自动析构释放内存。

不过这样做存在问题:

  • 若对话框不是在一个界面类中出现,由于QWidget的parent必须是QWidget指针,就不能将普通的 C++ 类指针传给 Qt 对话框。
  • 另外如果对内存占用有严格限制,当将主窗口作为parent时,若主窗口不关闭对话框就不会被销毁,导致会一直占用内存。

在这种情景下可以设置dialog的WindowAttribute解决:函数设置对话框关闭时,自动销毁对话框。

QDialog *dialog = new QDialog(this);//对象创建在堆区(匿名函数释放后 dialog对象不会释放)
dialog->resize(400, 300);
dialog->setWindowTitle("modalless dialog");
dialog->setAttribute(Qt::WA_DeleteOnClose);//防止用户重复操作 多次在堆区开辟内存 导致内存泄露
dialog->show();
qDebug() << "modalless dialog poped up.";
3.练习代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow) {
    ui->setupUi(this);
    //点击按钮 弹出对话框
    connect(ui->actionnew, &QAction::triggered, this, [=](){
        QDialog dialog(this);//对象创建在栈上(匿名函数释放后 dialog对象会释放)
        dialog.resize(400, 300);
        dialog.setWindowTitle("modal dialog");
        dialog.exec();
        qDebug() << "modal dialog poped up.";
    });
    connect(ui->actionopen, &QAction::triggered, this, [=](){
        QDialog *dialog = new QDialog(this);//对象创建在堆区(匿名函数释放后 dialog对象不会释放)
        dialog->resize(400, 300);
        dialog->setWindowTitle("modalless dialog");
        dialog->setAttribute(Qt::WA_DeleteOnClose);//防止用户重复操作 多次在堆区开辟内存 导致内存泄露
        dialog->show();
        qDebug() << "modalless dialog poped up.";
    });
}

MainWindow::~MainWindow() {
    delete ui;
}

二、标准对话框

1.消息对话框

QMessageBox用于显示消息提示。我们一般会使用其提供的几个 static 函数:

  • about:显示关于对话框。
  • aboutQt:显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。
  • critical:显示严重错误对话框。
  • information:与QMessageBox::critical()类似,不同之处在于这个对话框提供一个普通信息图标。
  • question:与QMessageBox::critical ()类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”。
  • warning:与QMessageBox::critical()类似,不同之处在于这个对话框提供一个黄色叹号图标。

使用QMessageBox::question()来询问一个问题,关于函数参数的解释:

  • 这个对话框的父窗口是 this。QMessageBox是QDialog的子类,这意味着它的初始显示位置将会是在 parent 窗口的中央。

  • 第二个参数是对话框的标题。

  • 第三个参数是我们想要显示的内容。

  • 第四个参数是关联的按键类型,我们可以使用或运算符(|)指定对话框应该出现的按钮。比如我们希望是一个 Yes 和一个 No。

  • 最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。

QMessageBox使用案例:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QDebug>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow) {
    ui->setupUi(this);
    //点击按钮 弹出对话框
    connect(ui->actionnew, &QAction::triggered, this, [=](){
        QDialog dialog(this);//对象创建在栈上(匿名函数释放后 dialog对象会释放)
        dialog.resize(400, 300);
        dialog.setWindowTitle("modal dialog");
        dialog.exec();
        qDebug() << "modal dialog poped up.";
    });
    connect(ui->actionopen, &QAction::triggered, this, [=](){
        QDialog *dialog = new QDialog(this);//对象创建在堆区(匿名函数释放后 dialog对象不会释放)
        dialog->resize(400, 300);
        dialog->setWindowTitle("modalless dialog");
        dialog->setAttribute(Qt::WA_DeleteOnClose);//防止用户重复操作 多次在堆区开辟内存 导致内存泄露
        dialog->show();
        qDebug() << "modalless dialog poped up.";
    });
    //点击按钮 弹出消息对话框
    connect(ui->actionwelcome, &QAction::triggered, this, [=](){
        QMessageBox::information(this, "welcome", "welcome to this application!~  ");
        qDebug() << "critical message box poped up.";
    });
    connect(ui->actionedit, &QAction::triggered, this, [=](){
        QMessageBox::critical(this, "sorry", "being developing, looking forward to more content.");
        qDebug() << "critical message box poped up.";
    });
    connect(ui->actionhelp, &QAction::triggered, this, [=](){
        QMessageBox::StandardButton choose;
        choose = QMessageBox::question(this, "question?", "Is there any problem when using this product? ");
        if (choose == QMessageBox::Yes) {
            qDebug() << "User have question about the use of the software.";
        } else if (choose == QMessageBox::No) {
            qDebug() << "User have no question about the use of the software.";
        }
        qDebug() << "question message box poped up.";
    });
    connect(ui->actionproject, &QAction::triggered, this, [=](){
        QMessageBox::warning(this, "warning", "project cannot be edit now.");
        qDebug() << "question message box poped up.";
    });
}

MainWindow::~MainWindow() {
    delete ui;
}

自定义细节QMessageBox细节

QMessageBox类的 static 函数优点是方便使用,缺点是非常不灵活。只能使用简单的几种形式。为了能够定制QMessageBox细节,必须使用QMessageBox的属性设置 API。如果希望制作一个询问是否保存的对话框,可以使用如下的代码:

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow) {
    ui->setupUi(this);
    //点击save按钮 弹出save对话框(模态对话框)
    connect(ui->actionsave, &QAction::triggered, this, [=](){
        QMessageBox msgBox(this);
        msgBox.setText(tr("The document has been modified."));
        msgBox.setInformativeText(tr("Do you want to save your changes?"));
        msgBox.setDetailedText(tr("Differences here..."));
        msgBox.setStandardButtons(QMessageBox::Save
                                  | QMessageBox::Discard
                                  | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        int ret = msgBox.exec();
        switch (ret) {
        case QMessageBox::Save:
            qDebug() << "Save document!";
            break;
        case QMessageBox::Discard:
            qDebug() << "Discard changes!";
            break;
        case QMessageBox::Cancel:
            qDebug() << "Close document!";
            break;
        }
    });
}

msgBox 是一个建立在栈上的QMessageBox实例。

设置其主要文本信息为 The document has been modified.,informativeText 则是会在对话框中显示的简单说明文字。使用了detailedText详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。

自定义的对话框的按钮有三个:保存、丢弃和取消。最后我们使用了exec()是其成为一个模态对话框,根据其返回值进行相应的操作。

2.文件对话框
  1. 首先需要创建一个带有文本编辑功能的窗口

    QAction *openAction = ui->actionopen;
    QAction *saveAction = ui->actionsave;
    //设置按钮图片
    openAction->setIcon(QIcon(":/res/img/ParticleSmoke.png"));
    saveAction->setIcon(QIcon(":/res/img/filetransfer.png"));
    //设置按钮提示tips
    openAction->setStatusTip(tr("Open an existing file"));
    saveAction->setStatusTip(tr("Save a new file"));
    //设置中心组件为textEdit
    QTextEdit *textEdit = new QTextEdit(this);
    
  2. 使用connect()函数,为这两个QAction对象添加响应的动作:

    connect(openAction, &QAction::triggered, this, &MainWindow::openFile);
    connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
    
  3. 编写核心的逻辑处理openFile()saveFile() 函数:

    //打开文件
    void MainWindow::openFile() {
        QString filepath = QFileDialog::getOpenFileName(this, tr("Open File"), ".", tr("Text Files(*.txt)"));
        if(!filepath.isEmpty()) {
            QFile file(filepath);
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                QMessageBox::warning(this, tr("Read File"), tr("Cannot open file:\n%1").arg(filepath));
                return;
            }
            QTextStream in(&file);
            textEdit->setText(in.readAll());
            file.close();
        } else {
            QMessageBox::warning(this, tr("Path"), tr("You did not select any file."));
        }
    }
    
    //保存文件
    void MainWindow::saveFile() {
        QString filepath = QFileDialog::getSaveFileName(this, tr("Open File"), ".", tr("Text Files(*.txt)"));
        if(!filepath.isEmpty()) {
            QFile file(filepath);
            if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
                QMessageBox::warning(this, tr("Write File"), tr("Cannot open file:\n%1").arg(filepath));
                return;
            }
            QTextStream out(&file);
            out << textEdit->toPlainText();
            file.close();
        } else {
            QMessageBox::warning(this, tr("Path"), tr("You did not select any file."));
        }
    }
    
  4. 在openFile()函数中,我们使用QFileDialog::getOpenFileName()来获取需要打开的文件的路径。这个函数原型如下:

    QString getOpenFileName(QWidget * parent = 0,
                            const QString & caption = QString(),
                            const QString & dir = QString(),
                            const QString & filter = QString(),
                            QString * selectedFilter = 0,
                            Options options = 0)
    
    • parent:父窗口,Qt 的标准对话框提供静态函数,用于返回一个模态对话框;

    • caption:对话框标题,

    • dir:对话框打开时的默认目录

      . 代表程序运行目录

      / 代表当前盘符的根目录(特指 Windows 平台;Linux 平台当然就是根目录),这个参数也可以是平台相关的,比如“C:\”等;

    • filter:过滤器,我们使用文件对话框可以浏览很多类型的文件,但是,很多时候我们仅希望打开特定类型的文件。比如,文本编辑器希望打开文本文件,图片浏览器希望打开图片文件。过滤器就是用于过滤特定的后缀名。如果我们使用“Image Files(*.jpg *.png)”,则只能显示后缀名是 jpg 或者 png 的文件。如果需要多个过滤器,使用“;;”分割,比如“JPEG Files(*.jpg);;PNG Files(*.png)”;

    • selectedFilter:默认选择的过滤器;

    • options:对话框的一些参数设定,比如只显示文件夹等等,它的取值是enum QFileDialog::Option,每个选项可以使用 | 运算组合起来。

saveFile()中使用的QFileDialog::getSaveFileName()也是类似的。使用这种静态函数,在 Windows、Mac OS 上面都是直接调用本地对话框,但是 Linux 上则是QFileDialog自己的模拟。这表明如果你不使用这些静态函数,而是直接使用QFileDialog进行设置,那么得到的对话框很可能与系统对话框的外观不一致(需要注意的)。文章来源地址https://www.toymoban.com/news/detail-686271.html

3.颜色对话框
//颜色对话框
connect(ui->actioncolor, &QAction::triggered, this, [=](){
    QColor color = QColorDialog::getColor(QColor(255, 0, 0));
    qDebug() << "red = " << color.red() << "green = " << color.green() << "blue = " << color.blue();
});
4.字体对话框
//字体对话框
connect(ui->actionfont, &QAction::triggered, this, [=](){
    bool flag;
    QFont font = QFontDialog::getFont(&flag, QFont("方正喵呜简体", 18));
    qDebug() << "font-family:" << font.family() << "font-size:" << font.pointSize()
    << "isBold:" << font.bold() << "isitalic:" << font.italic();
    qDebug() << "QFileDialog poped up.";
});

到了这里,关于【Qt学习】04:QDialog的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT客户端开发的应用场景

    QT 是一跨平台应用程序开发框架,支持多种操作系统,包括 Windows、macOS、Linux、Android、iOS 和嵌入式系统等。这使得 QT 非常适合开发需要在多种平台上运行的应用程序。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 QT 提供了一套完整的开发工具和

    2024年04月29日
    浏览(30)
  • Qt 8. UDP客户端通信

    1. 代码 2. 效果 以上代码可以实现UDP收发功能。

    2024年02月13日
    浏览(31)
  • 【Qt专栏】Qt实现TCP服务端和客户端通信

    网络通信是程序员必须会的一项生存技能,这里简单的实现了服务端和客户端通信的两个小示例,代码可以直接拿来用,开发环境是Qt5.9.6。 1.项目架构 2.tcpserver.h文件 3.tcpserver.cpp文件 4.测试效果 1.项目架构 2.tcpserver.h文件 3.tcpserver.cpp文件 4.测试效果 好了,两个小程序写完并

    2024年02月12日
    浏览(29)
  • Qt 服务器/客户端TCP通讯

    最近需要用到TCP/IP通讯,这边就先找个简单的例程学习一下。Qt的TCP通讯编程可以使用QtNetwork模块,QtNetwork模块提供的类能够创建基于TCP/IP的客户端与服务端应用程序,一般会使用QTcpSocket、QTcpServer类 网络通信方式主要有两种:TCP与UDP。以下拷贝网络上总结两者之间的区别:

    2023年04月26日
    浏览(57)
  • QT实现tcp服务器客户端

    2024年02月07日
    浏览(42)
  • 【QT 网络云盘客户端】——实现文件属性窗口

    目录 文件属性对话框 设置字体样式  获取文件的信息 显示文件属性对话框 当我们点击文件中的属性,则会弹出一个属性对话框:    实现过程: 0. 设置 属性 菜单项的槽函数 。 1.鼠获取鼠标选中的 QListWidgetItem ,它包含 图标 和 文件名 2.根据 文件名 找到对应的 FileInfo对象

    2024年02月15日
    浏览(28)
  • 《QT从基础到进阶·十六》QT实现客户端和服务端的简单交互

    QT版本:5.15.2 VS版本:2019 客户端程序主要包含三块:连接服务器,发送消息,关闭客户端 服务端程序主要包含三块:打开消息监听,接收消息并反馈,关闭服务端 1、先打开服务端监听功能 2、点击客户端connect连接服务端 3、在客户端输入消息点击send发送到服务端 4、在服务

    2024年02月03日
    浏览(27)
  • QT充当客户端模拟浏览器等第三方客户端对https进行双向验证

    在 ssl单向证书和双向证书校验测试及搭建流程 文章中,已经做了基于https的单向认证和双向认证,,, 在进行双向认证时,采用的是curl工具或浏览器充当客户端去验证。 此次采用QT提供的接口去开发客户端向服务器发送请求,来验证https的双向认证流程。 依然以 ssl单向证书

    2024年02月14日
    浏览(40)
  • 【QT 网络云盘客户端】——主窗口界面的设计

    目录 1.设计主窗口界面   2.设置窗口的背景图片 3. 自定义标题栏  3.1 设置toolbutton按钮的图片  3.2 设置按钮的大小 3.3 将自定义标题栏添加设置到主页面中  3.4 去除窗口的原标题栏  3.5 设置按钮颜色 3.6 切换页面功能实现 4.我的文件页面的设计 4.1 菜单栏的设计 4.2 自定义

    2024年02月15日
    浏览(25)
  • Qt实现客户端与服务器消息发送

    里用Qt来简单设计实现一个场景,即: (1)两端:服务器QtServer和客户端QtClient (2)功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度。 环境:VS20013 + Qt5.11.2 + Qt设计师 先看效果: 客户端与服务器的基本概念不说了,关于TCP通信的三次握

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包