[学习][笔记] qt5 从入门到入坟:<六>对话框

简介: [学习][笔记] qt5 从入门到入坟:<六>对话框

对话框

对话框是 GUI程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。

对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。

Qt中使用QDialog类实现对话框。就像主窗口一样,我们通常会设计一个类继承QDialog。QDialog(及其子类,以及所有Qt::Dialog类型的类)的对于其parent 指针都有额外的解释:

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

模态对话框和非模态对话框

所谓模态对话框,就是会阻塞同一应用程序中其它窗口的输入。

模态对话框很常见,比如“打开文件”功能。你可以尝试一下记事本的打开文件,当打开文件对话框出现时,我们是不能对除此对话框之外的窗口部分进行操作的。

与此相反的是非模态对话框,例如查找对话框,我们可以在显示着查找对话框的同时,继续对记事本的内容进行编辑。

应用程序级别的模态和窗口级别的模态

应用程序级别的模态和窗口级别的模态,默认是应用程序级别的模态。应用程序级别的模态是指,当该种模态的对话框出现时,用户必须首先对对话框进行交互,直到关闭对话框,然后才能访问程序中其他的窗口。窗口级别的模态是指,该模态仅仅阻塞与对话框关联的窗口,但是依然允许用户与程序中其它窗口交互。窗口级别的模态是指,该模态仅仅阻塞与对话框关联的窗口,但是依然允许用户与程序中其它窗口交互。窗口级别的模态尤其适用于多窗口模式。

使用QDialog::exec()实现应用程序级别的模态对话框;

使用QDialog::open()实现窗口级别的模态对话框;

使用QDialog::show()实现非模态对话框。

栈上创建dialog和堆上创建dialog区别

栈上创建dialog

//QDialog dialog(this);// have parent,just fix on the MainWindow
    QDialog dialog;//no parent ,this dialog can be put on anywhere
    dialog.setWindowTitle(tr("Hello, dialog!"));
    //dialog.exec();// 应用级别模态框
    //dialog.open();// 窗口级别模态框
    dialog.show();// 非模态框

会发现dialog一闪而过,因为dialog作用域结束,就生命周期终结。

堆上创建dialog

QDialog* ptrDialog = new QDialog(this);
    ptrDialog->setWindowTitle("hello,dialog!");
    ptrDialog->open();

堆上则不会,可能存在内存泄漏,但是我们将dialog作为了mainWindow的子控件,则由mainWindow管理dialog生命周期。但是会限制dialog的位置只能在mainWindow里面。另一解决办法:

QDialog *dialog = new QDialog;
    dialog->setAttribute(Qt::WA_DeleteOnClose);//关闭对话框时销毁,同时无法传递数据给窗口
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->show();

需要注意的一点是,如果我们设置 dialog 的属性为WA_DeleteOnClose,那么当对话框关闭时,对象被销毁,我们就不能使用这种办法获取数据了。在这种情况下,我们可以考虑使用 parent 指针的方式构建对话框,避免设置WA_DeleteOnClose属性;或者是利用另外的方式。

另外,QObject还有一个deleteLater()函数,该函数会在当前事件循环结束时销毁该对话框(具体到这里,需要使用exec()开始一个新的事件循环)。关于事件循环,我们会在后面的文章中详细说明。

对话框数据传递

exec(),show() 对于数据传递

exec()阻塞传递

exec()函数的真正含义是开启一个新的事件循环(我们会在后面的章节中详细介绍有关事件的概念)。所谓事件循环,可以理解成一个无限循环。Qt在开启了事件循环之后,系统发出的各种事件才能够被程序监听到。

同时exec是阻塞的 对话框关闭才会执行完 拥有返回值

QDialog::Accepted 代表点击yes

QDialog::Rejected 代表取消对话框或者no

QDialog::show()函数会立即返回,如果我们也这么写,就不可能取得用户输入的数据。因为show()函数不会阻塞主线程,show()立即返回,用户还没有来得及输入,就要执行后面的代码,当然是不会有正确结果的。那么我们就应该换一种思路获取数据,那就是使用信号槽机制。

由于非模态对话框在关闭时可以调用QDialog::accept()或者QDialog::reject()或者更通用的QDialog::done()函数,所以我们可以在这里发出信号。另外,如果找不到合适的信号发出点,我们可以重写QDialog::closeEvent()函数,在这里发出信号。在需要接收数据的窗口(这里是主窗口)连接到这个信号即可。

show() 异步传递数据

以下代码就是通过信号槽方式 dialog.show() 异步传递数据

关闭dialog时 就会出发信号 然后修改userAge值

//userAgeDialog.h
class UserAgeDialog :public QDialog{
    Q_OBJECT
public:
    UserAgeDialog(QWidget *parent = nullptr);
    ~UserAgeDialog();
    void reject() override{
        emit userAgeChanged(newAge); // newAge is an int
        QDialog::reject();
    };
Q_SIGNALS:
    void userAgeChanged(int);
private:
    int newAge = 100;
};
//userAgeDialog.cpp
#include "userAgeDialog.h"
UserAgeDialog::UserAgeDialog(QWidget *parent)
{
}
UserAgeDialog::~UserAgeDialog()
{
}
//mainwindow.h
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void setUserAge(int);
    void showUserAgeDialog();
     int userAge = 0;
private:
    Ui::MainWindow *ui;
};
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "userAgeDialog.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::setUserAge(int age)
{
    userAge = age;
}
void MainWindow::showUserAgeDialog(){
    UserAgeDialog *dialog = new UserAgeDialog(this);
    connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
    dialog->show();
}
//main.cpp
/***
 *
 *
 *  code means
 *  when close the dialog,will change userAge, and emit some message ;
 *
***/
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    w.showUserAgeDialog();
    a.exec();
    qDebug()<<w.userAge;
    return 0;
}

不要担心如果对话框关闭,是不是还能获取到数据。因为 Qt 信号槽的机制保证,在槽函数在调用的时候,我们始终可以使用sender()函数获取到

signal的发出者。关于sender()函数,可以在文档中找到更多的介绍。顺便说一句,sender()函数的存在使我们可以利用这个函数,来实现一个只能打开一个的非模态对话框(方法就是在对话框打开时在一个对话框映射表中记录下标记,在对话框关闭时利用sender()函数判断是不是该对话框,然后从映射表中将其删除)。

标准对话框 QMessageBox

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

QColorDialog:选择颜色;

QFileDialog:选择文件或者目录;

QFontDialog:选择字体;

QInputDialog:允许用户输入一个值,并将其值返回; QMessageBox:模态对话框,用于显示信息、询问问题等;

QPageSetupDialog:为打印机提供纸张相关的选项;

QPrintDialog:打印机配置;

QPrintPreviewDialog:打印预览;

QProgressDialog:显示操作过程。

静态函数方法 使用QMessageBox

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

void about(QWidget * parent, const QString & title, const QString & text):显示关于对话框。这是一个最简单的对话框,其标题是 title,内容是 text,父窗口是 parent。对话框只有一个 OK按钮。

void aboutQt(QWidget * parent, const QString & title = QString()):显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。

StandardButton critical(QWidget * parent, const QString & title, const QString & text,StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):显示严重错误对话框。这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明其显示的按钮。默认情况下只有一个 Ok 按钮,我们可以使用StandardButtons类型指定多种按钮。

StandardButton information(QWidget * parent, const QString & title, const QString & text,StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::information()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个普通信息图标。

StandardButton question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton):QMessageBox::question()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”两个。

StandardButton warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):QMessageBox::warning()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个黄色叹号图标。

创建QMessageBox实例 使用QMessageBox

msgBox 是一个建立在栈上的QMessageBox实例。我们设置其主要文本信息为“The document has been modified.”,informativeText 则是会在对话框中显示的简单说明文字。

下面我们使用了一个detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了exec()是其成为一个模态对话框,根据其返回值进行相应的操作。

QMessageBox msgBox;
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;
}

除去对话框样式,我们值得注意的是QMessageBox下方按钮的排列顺序。KDE 上是 ShowDetails…、Save、Discard 和 Cancel;而 Windows 7 上则是 Save、Discard、Show Details… 和 Cancel。我们并没有指定按钮的顺序,Qt 已经帮我们按照不同平台的使用习惯对其进行了调整。这一点在 Mac OS 上也会有相应的体现。对于一个普通的QDialog而言,Qt 使用的是QDialogButtonBox这个类来实现不同平台的对话框按钮顺序的显示的。更多细节请参考这个类的文档。

Qt 学习之路 2(15):标准对话框 QMessageBox

文件对话框

Qt 学习之路 2(17):文件对话框


相关文章
|
2月前
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
168 4
|
3月前
|
数据挖掘 C++
QT基础入门——项目案例(七)
QT基础入门——项目案例(七)
97 0
QT基础入门——项目案例(七)
|
3月前
|
API
QT基础入门——Qt事件(五)
QT基础入门——Qt事件(五)
54 0
QT基础入门——Qt事件(五)
|
3月前
|
Unix Java Linux
QT基础入门——认识与创建QT(一)
QT基础入门——认识与创建QT(一)
62 0
QT基础入门——认识与创建QT(一)
|
4月前
Qt6学习笔记五(自定义对话框、QMessageBox、QColorDialog、QFileDialog、QFontDialog)
Qt6学习笔记五(自定义对话框、QMessageBox、QColorDialog、QFileDialog、QFontDialog)
42 0
|
2月前
|
Linux 编译器 API
探索Qt图像处理的奥秘:从入门到精通
探索Qt图像处理的奥秘:从入门到精通
85 2
|
2月前
|
SQL 存储 关系型数据库
【C/C++ 应用开发 数据库】入门 Qt数据库编程:从基本操作到高级技巧
【C/C++ 应用开发 数据库】入门 Qt数据库编程:从基本操作到高级技巧
80 0
|
3月前
|
编解码
QT基础入门——文件操作(六)
QT基础入门——文件操作(六)
27 0
QT基础入门——文件操作(六)
|
3月前
|
容器
QT基础入门——界面布局和常用控件(四)
QT基础入门——界面布局和常用控件(四)
38 0
QT基础入门——界面布局和常用控件(四)
|
3月前
|
存储
QT基础入门——QMainWindow与对话框QDialog(三)
QT基础入门——QMainWindow与对话框QDialog(三)
55 0
QT基础入门——QMainWindow与对话框QDialog(三)

推荐镜像

更多