Qt 高级开发 010: 从跨界面传值到自定义信号
- 一、项目初始化:搭建主界面与弹窗窗口
-
- [1. 主界面设计](#1. 主界面设计)
- [2. 创建弹窗窗口](#2. 创建弹窗窗口)
- 二、自定义信号:声明→发送→绑定,三步吃透
-
- [1. 声明自定义信号](#1. 声明自定义信号)
- [2. 发送信号](#2. 发送信号)
- [3. 主界面绑定信号与槽](#3. 主界面绑定信号与槽)
- [三、致命坑点:exec () 事件循环阻塞,信号不触发!](#三、致命坑点:exec () 事件循环阻塞,信号不触发!)
- [四、进阶优化:实现点击一次、数值 + 1](#四、进阶优化:实现点击一次、数值 + 1)
- 五、核心知识点总结(必记!)
- 六、写在最后
在 Qt 开发的世界里,信号与槽 是贯穿始终的核心通信机制,它像一座精巧的桥梁,让不同界面、不同模块之间的数据传递变得优雅又高效。很多初学者刚接触时,总会被 "信号怎么定义、槽函数怎么绑定、数据怎么跨界面传递" 等问题困住,今天我们就从一个完整的实战案例出发,一步步拆解自定义信号 + 跨界面传值的完整流程,把每一个细节、每一个坑点都讲透,让你彻底掌握这一核心技能🚀
一、项目初始化:搭建主界面与弹窗窗口
我们先创建一个 Qt Widgets 项目,命名为 init_signal_two_UI,以此为载体实现 "主界面打开弹窗 → 弹窗发送数据 → 主界面接收并显示" 的完整逻辑。
1. 主界面设计
在主界面拖拽两个核心控件:
-
按钮:
btn_open(文本:打开设置窗口) -
输入框:
lineEdit(用于接收弹窗传递的数据)
为按钮绑定槽函数 ,这是 Qt 交互的基础,槽函数返回值固定为 void,命名遵循 on_控件名_信号名 规范:
cpp
// 槽函数声明
private slots:
void on_btn_open_clicked();
2. 创建弹窗窗口
右键项目 → 添加新文件 → Qt → 设计师界面类,选择 Dialog 弹窗(轻量、适合临时交互),命名为 GitDownloadDialog。
在弹窗界面添加一个按钮:btn_add,后续通过这个按钮触发信号,向主界面发送数据。
二、自定义信号:声明→发送→绑定,三步吃透
信号是 Qt 中对象间通信的信使 ,它无需实现,只需声明,且返回值必须是 ****void,这是 Qt 信号的铁律!
1. 声明自定义信号
在弹窗类 GitDownloadDialog 中,使用 signals 关键字声明信号,信号可以携带参数,用于传递数据:
cpp
// GitDownloadDialog.h
signals:
// 自定义信号:携带一个int类型参数,用于传递数值
void sig_add_one(int value);
2. 发送信号
弹窗按钮点击时,用 emit 关键字触发信号,并携带要传递的数据:
cpp
// GitDownloadDialog.cpp
void GitDownloadDialog::on_btn_add_clicked()
{
// 发送信号,携带数值100
emit sig_add_one(100);
}
3. 主界面绑定信号与槽
信号发送后,主界面需要监听并接收 ,这一步用 connect 函数完成绑定,推荐用 Lambda 表达式简化槽函数编写:
cpp
// 主界面槽函数:打开弹窗并绑定信号
void Widget::on_btn_open_clicked()
{
// 创建弹窗对象
GitDownloadDialog dlg;
// ✨ 关键:绑定信号与Lambda槽函数
connect(&dlg, &GitDownloadDialog::sig_add_one, this, [=](int val){
// int转QString,显示到输入框
ui->lineEdit->setText(QString::number(val));
});
// 弹窗阻塞执行(模态弹窗)
dlg.exec();
}
三、致命坑点:exec () 事件循环阻塞,信号不触发!
代码写完运行,你会发现点击弹窗按钮,主界面完全收不到数据 ,这是新手最容易踩的顶级坑!
问题根源
dlg.exec() 会启动模态事件循环 ,阻塞当前线程 ,后续所有代码都不会执行!也就是说,我们的 connect 绑定逻辑,根本没机会运行!
正确写法
绑定必须放在 exec () 之前,先绑定信号,再弹出窗口,顺序绝对不能乱:
cpp
void Widget::on_btn_open_clicked()
{
GitDownloadDialog dlg;
// 1. 先绑定信号(核心!)
connect(&dlg, &GitDownloadDialog::sig_add_one, this, [=](int val){
ui->lineEdit->setText(QString::number(val));
});
// 2. 后弹出弹窗
dlg.exec();
}
修正后运行,点击弹窗的 add 按钮,主界面输入框会立刻显示 100,跨界面传值成功🎉
四、进阶优化:实现点击一次、数值 + 1
基础传值搞定后,我们升级需求:让弹窗每次点击,数值自动 + 1,只需定义一个变量记录当前值,发送时自增即可:
cpp
// GitDownloadDialog.cpp
void GitDownloadDialog::on_btn_add_clicked()
{
static int num = 100; // 静态变量,保留上次值
emit sig_add_one(num);
num++; // 每次发送后+1
}
此时点击 add 按钮,主界面会显示 100 → 101 → 102...,动态传值完美实现。
五、核心知识点总结(必记!)
-
信号声明规则
-
用
signals关键字声明,返回值必须是void -
无需实现,只需定义名称与参数
-
类必须继承
QObject(Qt 窗口类默认继承,无需手动处理)
-
-
信号发送规则
-
用
emit关键字触发信号 -
信号参数会随发送动作传递给槽函数
-
-
绑定与执行顺序
-
connect绑定必须在exec()/show()之前 -
exec()阻塞 UI,适合模态弹窗;show()非阻塞,适合非模态窗口
-
-
数据类型转换
-
数值转字符串:
QString::number(int value) -
字符串转数值:
lineEdit->text().toInt()
-
六、写在最后
跨界面传值是 Qt 信号槽最基础、最常用的场景,看似简单,却藏着 exec() 阻塞、绑定顺序、类型转换等细节。只要牢牢记住 "先绑定、后弹窗" 的核心原则,再配合自定义信号的声明与发送流程,就能轻松搞定所有界面间的通信需求。

下一篇我们将进阶讲解跨线程信号槽,解决子线程不能操作 UI 的核心问题,持续关注,带你从 Qt 新手快速进阶为实战高手💪