#(14):对话框数据传递
对话框的出现用于完成一个简单的或者是短期的任务。对话框与主窗口之间的数据交互相当重要。本节将讲解如何在对话框和主窗口之间进行数据交互。按照前文的讲解,对话框分为模态和非模态两种。我们也将以这两种为例,分别进行阐述。
模态对话框使用了`exec()`函数将其显示出来。`exec()`函数的真正含义是开启一个新的事件循环(我们会在后面的章节中详细介绍有关事件的概念)。所谓事件循环,可以理解成一个无限循环。Qt 在开启了事件循环之后,系统发出的各种事件才能够被程序监听到。这个事件循环相当于一种轮询的作用。既然是无限循环,当然在开启了事件循环的地方,代码就会被阻塞,后面的语句也就不会被执行到。因此,对于使用了`exec()`显示的模态对话框,我们可以在`exec()`函数之后直接从对话框的对象获取到数据值。
看一下下面的代码:
~~~
void MainWindow::open()
{
QDialog dialog(this);
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.exec();
qDebug() << dialog.result();
}
~~~
上面的代码中,我们使用`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`。一般我们会使用类似下面的代码:
~~~
QDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
// do something
} else {
// do something else
}
~~~
来判断对话框的返回值,也就是用户是点击了“确定”还是“取消”。更多细节请参考`QDialog`文档。
模态对话框相对简单,如果是非模态对话框,`QDialog::show()`函数会立即返回,如果我们也这么写,就不可能取得用户输入的数据。因为`show()`函数不会阻塞主线程,`show()`立即返回,用户还没有来得及输入,就要执行后面的代码,当然是不会有正确结果的。那么我们就应该换一种思路获取数据,那就是使用信号槽机制。
由于非模态对话框在关闭时可以调用`QDialog::accept()`或者`QDialog::reject()`或者更通用的`QDialog::done()`函数,所以我们可以在这里发出信号。另外,如果找不到合适的信号发出点,我们可以重写`QDialog::closeEvent()`函数,在这里发出信号。在需要接收数据的窗口(这里是主窗口)连接到这个信号即可。类似的代码片段如下所示:
~~~
//!!! Qt 5
// in dialog:
void UserAgeDialog::accept()
{
emit userAgeChanged(newAge); // newAge is an int
QDialog::accept();
}
// in main window:
void MainWindow::showUserAgeDialog()
{
UserAgeDialog *dialog = new UserAgeDialog(this);
connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
dialog->show();
}
// ...
void MainWindow::setUserAge(int age)
{
userAge = age;
}
~~~
上面的代码很简单,这里不再赘述。另外,上述代码的 Qt 4 版本也应该可以很容易地实现。
不要担心如果对话框关闭,是不是还能获取到数据。因为 Qt 信号槽的机制保证,在槽函数在调用的时候,我们始终可以使用`sender()`函数获取到 signal 的发出者。关于`sender()`函数,可以在文档中找到更多的介绍。顺便说一句,`sender()`函数的存在使我们可以利用这个函数,来实现一个只能打开一个的非模态对话框(方法就是在对话框打开时在一个对话框映射表中记录下标记,在对话框关闭时利用`sender()`函数判断是不是该对话框,然后从映射表中将其删除)。
- (1)序
- (2)Qt 简介
- (3)Hello, world!
- (4)信号槽
- (5)自定义信号槽
- (6)Qt 模块简介
- (7)MainWindow 简介
- (8)添加动作
- (9)资源文件
- (10)对象模型
- (11)布局管理器
- (12)菜单栏、工具栏和状态栏
- (13)对话框简介
- (14)对话框数据传递
- (15)标准对话框 QMessageBox
- (16)深入 Qt5 信号槽新语法
- (17)文件对话框
- (18)事件
- (19)事件的接受与忽略
- (21)事件过滤器
- (22)事件总结
- (23)自定义事件
- (24)Qt 绘制系统简介
- (25)画刷和画笔
- (26)反走样
- (27)渐变
- (28)坐标系统
- (29)绘制设备
- (30)Graphics View Framework
- (31)贪吃蛇游戏(1)
- (32)贪吃蛇游戏(2)
- (33)贪吃蛇游戏(3)
- (34)贪吃蛇游戏(4)
- (35)文件
- (36)二进制文件读写
- (37)文本文件读写
- (38)存储容器
- (39)遍历容器
- (40)隐式数据共享
- (41)model/view 架构
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)视图和委托
- (47)视图选择
- (48)QSortFilterProxyModel
- (49)自定义只读模型
- (50)自定义可编辑模型
- (51)布尔表达式树模型
- (52)使用拖放
- (53)自定义拖放数据
- (54)剪贴板
- (55)数据库操作
- (56)使用模型操作数据库
- (57)可视化显示数据库数据
- (58)编辑数据库外键
- (59)使用流处理 XML
- (60)使用 DOM 处理 XML
- (61)使用 SAX 处理 XML
- (62)保存 XML
- (63)使用 QJson 处理 JSON
- (64)使用 QJsonDocument 处理 JSON
- (65)访问网络(1)
- (66)访问网络(2)
- (67)访问网络(3)
- (68)访问网络(4)
- (69)进程
- (70)进程间通信
- (71)线程简介
- (72)线程和事件循环
- (73)Qt 线程相关类
- (74)线程和 QObject
- (75)线程总结
- (76)QML 和 QtQuick 2
- (77)QML 语法
- (78)QML 基本元素
- (79)QML 组件
- (80)定位器
- (81)元素布局
- (82)输入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)动态视图
- (86)视图代理
- (87)模型-视图高级技术
- (88)Canvas
- (89)Canvas(续)