找回密码
 立即注册
收起左侧

Qt学习之路第14篇 对话框数据传递

11
回复
27429
查看
[复制链接]
累计签到:3 天
连续签到:1 天
来源: 2013-9-9 11:51:05 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
版权声明

该文章原创于Qter开源社区(www.qter.org),作者devbean,博客www.devbean.net,转载请注明出处!


对话框的出现用于完成一个简单的或者是短期的任务。对话框与主窗口之间的数据交互相当重要。本节将讲解如何在对话框和主窗口之间进行数据交互。按照前文的讲解,对话框分为模态和非模态两种。我们也将以这两种为例,分别进行阐述。



模态对话框使用了 exec() 函数将其显示出来。exec() 函数的真正含义是开启一个新的事件循环(我们会在后面的章节中详细介绍有关事件的概念)。所谓事件循环,可以理解成一个无限循环。Qt 在开启了事件循环之后,系统发出的各种事件才能够被程序监听到。这个事件循环相当于一种轮询的作用。既然是无限循环,当然在开启了事件循环的地方,代码就会被阻塞,后面的语句也就不会被执行到。因此,对于使用了 exec() 显示的模态对话框,我们可以在 exec() 函数之后直接从对话框的对象获取到数据值。



看一下下面的代码:

  1. void MainWindow::open()
  2. {
  3.     QDialog dialog(this);
  4.     dialog.setWindowTitle(tr("Hello, dialog!"));
  5.     dialog.exec();
  6.     qDebug() << dialog.result();
  7. }
复制代码

上面的代码中,我们使用 exec() 显示一个模态对话框。最后一行代码,qDebug() 类似于 std::cout 或者 Java 的 System.out.println(); 语句,将后面的信息输出到标准输出,一般就是控制台。使用 qDebug() 需要引入头文件。在 exec() 函数之后,我们直接可以获取到 dialog 的数据值。注意,exec() 开始了一个事件循环,代码被阻塞到这里。由于 exec() 函数没有返回,因此下面的 result() 函数也就不会被执行。直到对话框关闭,exec() 函数返回,此时,我们就可以取得对话框的数据。



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



实际上,QDialog::exec() 是有返回值的,其返回值是 QDialog::Accepted 或者 QDialog::Rejected。一般我们会使用类似下面的代码:

  1. QDialog dialog(this);
  2. if (dialog.exec() == QDialog::Accepted) {
  3.     // do something
  4. } else {
  5.     // do something else
  6. }
复制代码

来判断对话框的返回值,也就是用户是点击了“确定”还是“取消”。更多细节请参考 QDialog 文档。



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



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

  1. //!!! Qt 5
  2. // in dialog:
  3. void UserAgeDialog::accept()
  4. {
  5.     emit userAgeChanged(newAge); // newAge is an int
  6.     QDialog::accept();
  7. }

  8. // in main window:
  9. void MainWindow::showUserAgeDialog()
  10. {
  11.     UserAgeDialog *dialog = new UserAgeDialog(this);
  12.     connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
  13.     dialog->show();
  14. }

  15. // ...

  16. void MainWindow::setUserAge(int age)
  17. {
  18.     userAge = age;
  19. }
复制代码

上面的代码很简单,这里不再赘述。另外,上述代码的 Qt 4 版本也应该可以很容易地实现。



不要担心如果对话框关闭,是不是还能获取到数据。因为 Qt 信号槽的机制保证,在槽函数在调用的时候,我们始终可以使用 sender() 函数获取到 signal 的发出者。关于 sender() 函数,可以在文档中找到更多的介绍。顺便说一句,sender() 函数的存在使我们可以利用这个函数,来实现一个只能打开一个的非模态对话框(方法就是在对话框打开时在一个对话框映射表中记录下标记,在对话框关闭时利用 sender() 函数判断是不是该对话框,然后从映射表中将其删除)。







参与人数 1人气 +1 收起 理由
恒星shephered + 1 必须支持!

查看全部评分总评分 : 人气 +1

回复

使用道具 举报

累计签到:17 天
连续签到:1 天
2014-8-21 09:22:24 显示全部楼层
代码添加到哪里呀?不需要声明什么的吗
回复 支持 反对

使用道具 举报

累计签到:17 天
连续签到:1 天
2014-8-22 16:10:34 显示全部楼层
貌似继承了一个Dialog类
回复 支持 反对

使用道具 举报

累计签到:5 天
连续签到:1 天
2015-6-16 13:20:40 显示全部楼层
这次的代码不是很详尽,是继承了Qdialog,重写了accept方法吧
回复 支持 反对

使用道具 举报

累计签到:10 天
连续签到:1 天
2017-7-17 10:08:03 显示全部楼层
dialog这个类怎么弄的啊?
回复 支持 反对

使用道具 举报

尚未签到

2017-7-31 08:59:23 显示全部楼层
不详细,代码贴出来就好了
回复 支持 反对

使用道具 举报

累计签到:33 天
连续签到:1 天
2017-9-18 14:18:39 显示全部楼层
虚客 发表于 2015-6-16 13:20
这次的代码不是很详尽,是继承了Qdialog,重写了accept方法吧

看了下,是的。

额,还要30字,凑一下字数。
回复 支持 反对

使用道具 举报

尚未签到

2018-1-3 16:43:05 显示全部楼层
为什么没有完整代码有人知道原因么
回复 支持 反对

使用道具 举报

尚未签到

2018-3-25 15:50:05 显示全部楼层
发现设置dialog 的属性为 WA_DeleteOnClose时,依旧可以获取数据啊...
回复 支持 反对

使用道具 举报

尚未签到

2019-5-29 21:57:48 显示全部楼层
新建一个类UserDialog,继承QDialog就行啦;然后新建一个UI文件,UserUI;在MainWindow里实例化UserDialog并且利用UI文件serupUi一下就好啦
回复 支持 反对

使用道具 举报

累计签到:1 天
连续签到:1 天
2019-10-25 10:50:33 显示全部楼层
这个看不太懂啊 ,不知道怎么练习代码啊 ,谁能贴一下啊
回复 支持 反对

使用道具 举报

累计签到:1 天
连续签到:1 天
2019-10-25 15:07:14 显示全部楼层
Gambler 发表于 2019-10-25 10:50
这个看不太懂啊 ,不知道怎么练习代码啊 ,谁能贴一下啊

琢磨了一下,贴出来:
主窗口.h
  1. #include <QtWidgets/QMainWindow>
  2. #include "ui_QtDialogDataTransmit.h"
  3. #include "dialog.h"

  4. class QtDialogDataTransmit : public QMainWindow
  5. {
  6.         Q_OBJECT

  7. public slots:
  8.         void pressBtn();                //用户按下按钮
  9.         void updatedata(int newAge);                //数据更新

  10. public:
  11.         QtDialogDataTransmit(QWidget *parent = Q_NULLPTR);

  12. private:
  13.         Ui::QtDialogDataTransmitClass ui;
  14.         dialog* pDlg;
  15. };
复制代码


主窗口.cpp
  1. #include "QtDialogDataTransmit.h"
  2. #include "ui_QtDialogDataTransmit.h"

  3. QtDialogDataTransmit::QtDialogDataTransmit(QWidget *parent)
  4.         : QMainWindow(parent)
  5. {
  6.         ui.setupUi(this);
  7.         connect(ui.pushButton, &QPushButton::clicked, this, &QtDialogDataTransmit::pressBtn);
  8.         setWindowTitle(tr("Main Window"));
  9. }

  10. void QtDialogDataTransmit::pressBtn()
  11. {
  12.         pDlg = new dialog();
  13.         connect(pDlg, &dialog::userAgeChanged, this, &QtDialogDataTransmit::updatedata);

  14.         if (pDlg->exec() == QDialog::Accepted)
  15.         {
  16.                 delete pDlg;
  17.         }
  18.        
  19. }

  20. void QtDialogDataTransmit::updatedata(int newAge)
  21. {
  22.         ui.textEdit->append(QString::number(newAge));
  23. }
复制代码


弹窗.h
  1. #pragma once

  2. #include <QDialog>
  3. #include "ui_dialog.h"

  4. class dialog : public QDialog
  5. {
  6.         Q_OBJECT

  7. //信号函数:
  8. signals:
  9.         void userAgeChanged(int newAge);                //弹窗要发射的信号


  10.         //槽函数:
  11. public slots:
  12.         void pressBtn();


  13. public:
  14.         dialog(QWidget *parent = Q_NULLPTR);
  15.         ~dialog();

  16. private:
  17.         Ui::dialog ui;
  18. };
复制代码


弹窗。cpp
  1. #include "dialog.h"
  2. #include "ui_dialog.h"

  3. dialog::dialog(QWidget *parent)
  4.         : QDialog(parent)
  5. {
  6.         ui.setupUi(this);
  7.         connect(ui.pushButton, &QPushButton::clicked, this, &dialog::pressBtn);                //绑定单击按钮信号到槽函数 pressBtn
  8.         setWindowTitle(tr("Set Age"));
  9. }

  10. dialog::~dialog()
  11. {

  12. }

  13. void dialog::pressBtn()
  14. {
  15.         emit userAgeChanged(ui.lineEdit->text().toInt());
  16.         this->close();
  17. }
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了