Qt学习(七)—— QDialog

目录

模态和非模态对话框

模态对话框

非模态对话框

标准对话框和文件对话框

标准对话框

about()

question()

文件对话框 


模态和非模态对话框

当一个对话窗口弹出时,如果你不对它进行操作就无法操作其它窗口,这种对话框就成为模态对话框。反之则称为非模态对话框。

模态对话框

在Qt中,模态对话框是如何实现的呢?不仅需要用到QDialog类,还需要用到exec()。

在Qt的框架中有提到过,exec()使程序进入一个循环,直到用户进行操作才结束循环。所以,要实现模态对话框也需要用到它,只有当用户对对话框作出反馈,才能继续后续的操作。

下面用几行代码体会什么是模态对话框:

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QDebug>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QTextEdit>
#include <QDockWidget>
#include <QDialog>    //实现对话框必须引入的头文件
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //这部分代码省略
    QDialog *pDialog=new QDialog(this);
    pDialog->exec();    //注意是QDialog对象调用exec方法
    qDebug()<<"用户对模态对话框进行操作了";
}

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

实现效果:

由于这里没有往对话框里添加任何内容,所以出现的就是这么简单一个对话框,并且控制台中没有打印内容。下面我们点击“×”,关闭对话框。效果如下:

可以看到对话框消失了,主窗口才显示出来,同时控制台打印“用户对模态对话框进行操作了”,也就是说当用户对模态对话框进行反馈的动作之后,才会执行位于exec()方法后的语句。

注意:这里为什么对话框会先于主窗口出现呢?因为对话框定义在主窗口的构造函数中,包括它调用的exec方法,而主窗口只在自身的构造函数结束后,并调用show方法才会出现。 

如果将一个模态对话框定义在main.cpp中会怎么样?下面来看看这两种情况:

#include "MainWindow.h"
#include <QApplication>
#include <QDialog>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QDialog *pDialog=new QDialog();
    pDialog->exec();
    MainWindow w;
    w.show();


    return a.exec();
}

实现效果:

此时,只显示对话框,接着我们点击关闭按钮:

点击关闭按钮后,才执行exec()后面的语句。因此,这时候主窗口才显示出来。 

刚才,我们将模态对话框定义在主窗口之前,如果模态对话框定义在主窗口之后会发生什么?

#include "MainWindow.h"
#include <QApplication>
#include <QDialog>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    QDialog *pDialog=new QDialog();
    pDialog->exec();


    return a.exec();
}

实现效果:

虽然很糊(-_-||)还是可以看到,模态对话框一开始是被主窗口覆盖的,但是马上又跑到最前面了。 而且如果不关闭对话框,是没有办法操作后面的主窗口的。

非模态对话框

如果要实现非模态对话框,只要将exec()改为show()方法即可。

下面我们来实现点击菜单栏的“新建”按钮就会弹出一个非模态对话框的功能,代码如下:

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QDebug>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QTextEdit>
#include <QDockWidget>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //这部分代码省略,pCreate为QAction对象指针,在省略的代码中已定义
    connect(pCreate,&QAction::triggered,[=](){
        QDialog mDialog;
        mDialog.show();
        qDebug()<<"1111";
    });

}

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

实现效果:

可以看到(?)点击“新建”后,确实出现了一个对话框,但是马上就消失了。同时,控制台也打印了“1111”的内容,说明非模态对话框不需要等到用户进行反馈才执行show()方法之后的代码。 

但是!为什么对话框会消失呢?

这是因为,这个对话框mDialog是定义在栈里面的,同时还是一个局部变量,出了函数体后就会被内存自动回收,它就不存在了,所以也就消失了。

要解决这个问题,可以把mDialog作为主窗口类的成员变量,也可以用 new 关键字动态地为它申请内存,这样,就只有当我们用 delete 关键字手动释放这块内存时,它才会消失。 

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QDebug>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QTextEdit>
#include <QDockWidget>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //这部分代码省略,pCreate为QAction对象指针,在省略的代码中已定义
    connect(pCreate,&QAction::triggered,[=](){
        QDialog *mDialog=new QDialog(this);    //动态申请内存
        mDialog->show();
        qDebug()<<"1111";
    });

}

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

实现效果: 

这下,对话框就老老实实呆在这里了。当我们关闭主窗口时,对话框也会一起消失。此时,虽然我们没有手动用 delete 释放内存,但是由于它的父元素(也就是主窗口)在被关闭时,程序随之结束,它的析构函数被调用了,因此它下面所有子元素的析构也会被调用,并且先于主窗口被析构。【详见:https://blog.csdn.net/weixin_41001497/article/details/107181513

注意:用动态申请内存这种方式有一个缺点,就是它只有在程序结束时才释放内存,如果我们经常点击“新建”按钮,就会多次动态申请内存,这样一来也会造成内存泄漏的问题。所以,最好还是将对话框作为主窗口类的成员变量来定义。或者,在动态申请内存空间后,加上在每次关闭对话框时自动释放内存的一句代码。

QDialog *mDialog=new QDialog(this);         
mDialog->setAttribute(Qt::WA_DeleteOnClose);    //关闭对话框的同时,回收内存
mDialog->show();                            

标准对话框和文件对话框

标准对话框

在实际开发中,我们经常见到的还有标准对话框和文件对话框,什么是标准对话框?看图:

是不是非常熟悉?标准对话框是一种模式对话框,但是往往不直接用模式对话框来实现,因为这些按钮需要我们人为添加上去,要实现上面这种样式的对话框,有更简单的方法。

首先,要实现标准对话框需要先引入<QMessageBox>头文件。

about()

如果要实现一个程序中常常用来向用户描述介绍软件产品,并且只需要用户点击一个类似于“我知道了”的按钮的对话框,需要用到about方法。

调用QMessageBox类的about()函数,它的参数通过帮助文档可以知道,分别有“父元素”、“标题”、“内容”。

#include "MainWindow.h"
#include <QMenuBar>
#include <QMenu>
#include <QDebug>
#include <QToolBar>
#include <QPushButton>
#include <QStatusBar>
#include <QLabel>
#include <QTextEdit>
#include <QDockWidget>
#include <QDialog>
#include <QMessageBox>    //要使用标准对话框,必须引入的头文件
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //这部分代码省略,pCreate是一个QAction指针变量,在省略代码中已定义
        connect(pCreate,&QAction::triggered,[=](){
            QMessageBox::about(this,"create","新建");
        });
}

MainWindow::~MainWindow()
{

}

 实现效果:

可以看到点击“新建”按钮,会弹出一个标题为“create”,内容为“新建”的模态对话框。

P.S:

用下面的代码实现标准对话框,看起来效果也是一样的。

connect(pCreate,&QAction::triggered,[=](){    
    QMessageBox pMessageBox;                  
    pMessageBox.about(this,"haha","hoho");    
    //QMessageBox::about(this,"create","新建"); 
});                                           

question()

如果要实现一个询问用户是否进行某项操作的对话框,需要用到question方法。

调用QMessageBox类的question()函数,它的参数通过帮助文档可以知道,分别有“父元素”、“标题”、“内容”、“第一个按钮的值”、“第二个按钮的值”、“第三个按钮的值”。其中,第二个和第三个按钮的值默认为0,也就是说如果不对其进行设置的话,就认为是NoButton,也就是没有第二、三个按钮。

下面是只指定了第一个按钮的值的情况: 

connect(pCreate,&QAction::triggered,[=](){                        
   QMessageBox pMessageBox;                                       
    pMessageBox.question(this,"haha","hahaha",QMessageBox::Yes);  
});                                                               

 实现效果:

 下面是指定了三个按钮的值的情况: 

connect(pCreate,&QAction::triggered,[=](){                                                         
   QMessageBox pMessageBox;                                                                        
    pMessageBox.question(this,"haha","hahaha",QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel);
});                                                                                                

 实现效果:

注意:按钮不能超过三个,否则会报错。 

E:\Demo\QtDemo\BilibiliTest\06_QDialog\MainWindow.cpp:74: error: C2664: “int QMessageBox::question(QWidget *,const QString &,const QString &,QMessageBox::StandardButton,QMessageBox::StandardButton)”: 无法将参数 4 从“QMessageBox::StandardButton”转换为“const QString &”

下面是只给出前三个参数的值,没有给出按钮的值的情况:

connect(pCreate,&QAction::triggered,[=](){     
   QMessageBox pMessageBox;                    
    pMessageBox.question(this,"haha","hahaha");
});                                            

 实现效果:

QMessage::question()的返回值为int型,返回的是被用户点击的按钮对应的值,比如点击Yes返回16384(0x4000),点击No返回65535(0x10000),利用这个特性,可以配合switch语句,来处理用户不同的选择。 比如:

connect(pCreate,&QAction::triggered,[=](){              
   QMessageBox pMessageBox;                             
    int ret=pMessageBox.question(this,"haha","hahaha"); 
    switch(ret){                                        
    case QMessageBox::Yes:                              
        qDebug()<<"用户点击了Yes";                           
        break;                                          
    case QMessageBox::No:                               
        qDebug()<<"用户点击了No";                            
        break;                                          
        defaul:                                         
        break;                                          
    }                                                   
});                                                     

先后点击对话框的Yes按钮和No按钮,实现效果:

文件对话框 

文件对话框也是很常用的,比如我们经常需要在一个程序中打开一个已存在的项目,这时候就会弹出一个文件对话框。当我们选择完目标文件并点击确定后,文件完整的绝对路径就会作为一个字符串返回给我们。

要使用文件对话框,必须先引入<QFileDialog>头文件。

如果我们要获取打开的文件的路径,需要调用getOpenFileName方法。

P.S:

第一个参数parent,用于指定父组件。注意,很多Qt组件的构造函数都会有这么一个parent参数,并提供一个默认值0;
 
第二个参数caption,是对话框的标题;
 
第三个参数dir,是对话框显示时默认打开的目录,"." 代表程序运行目录,"/" 代表当前盘符的根目录(Windows,Linux下/就是根目录了),也可以是平台相关的,比如"C:\\"等;例如我想打开程序运行目录下的Data文件夹作为默认打开路径,这里应该写成"./Data/",若想有一个默认选中的文件,则在目录后添加文件名即可:"./Data/teaser.graph"
 
第四个参数filter,是对话框的后缀名过滤器,比如我们使用"Image Files(*.jpg *.png)"就让它只能显示后缀名是jpg或者png的文件。如果需要使用多个过滤器,使用";;"分割,比如"JPEG Files(*.jpg);;PNG Files(*.png)";
 
第五个参数selectedFilter,是默认选择的过滤器;
 
第六个参数options,是对话框的一些参数设定,比如只显示文件夹等等,它的取值是enum QFileDialog::Option,每个选项可以使用 | 运算组合起来。
 
如果我要想选择多个文件怎么办呢?Qt提供了getOpenFileNames()函数,其返回值是一个QStringList。你可以把它理解成一个只能存放QString的List,也就是STL中的list<string>。

【转自:https://blog.csdn.net/qq_38400517/article/details/78897446

connect(pCreate,&QAction::triggered,[=](){         
   QFileDialog::getOpenFileName(this,"open","../");    //相对路径是当前程序所在路径的上级目录
});                                                

 实现效果:

 如果我们还想指定文件类型的范围,则需要设定filter参数。这里同一个类型的不同文件后缀名用空格分隔,不同类型的文件用 ;; 分隔。

connect(pCreate,&QAction::triggered,[=](){                                                           
   QFileDialog::getOpenFileName(this,"open","../","source(*.cpp *.h);;image(*.jpg *.bmp);;all(*.*)");
});                                                                                                  

P.S:如果觉得字符串太长,可以用Enter键进行换行,C++会自动添加上缺少的双引号。 

实现效果:

P.S:如有错误,欢迎指正~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值