【Qt开发】信号与槽(三)-> 自定义信号和槽
目录
1 -> 基本语法
2 -> 带参数的信号和槽
3 -> 小结
1 -> 基本语法
在 Qt 中,允许自定义信号的发送方以及接收方,即可以自定义信号函数和槽函数。但是对于自定义的信号函数和槽函数有一定的书写规范。
一、自定义信号函数书写规范
- 自定义信号函数必须写到 “signals” 下
- 返回值为 void,只需要声明,不需要实现
- 可以有参数,也可以发生重载
二、自定义槽函数书写规范
- 早期的 Qt 版本要求槽函数必须写到 “public slots”下,但是现在高级版本的 Qt 允许写到类的 “public” 作用域中或者全局下
- 返回值为 void,需要声明,也需要实现
- 可以有参数,也可以发生重载
三、发送信号
使用 “emit” 关键字发送信号。“emit” 是一个空的宏。“emit” 其实是可选的,没有什么含义,只是为了提醒开发人员。
示例1:
1. 在 widget.h 中声明自定义的信号和槽
2. 在 widget.cpp 中实现槽函数,并且关联信号和槽
注意:下图中的 1 和 2 的顺序不可以颠倒
因为,首先关联信号和槽,一旦检测到信号发射之后就会立马执行关联的槽函数。反之,如若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应。
示例2:当老师说 “上课了”,学生们就 “回到座位,开始学习”
1. 在源文件中新建两个类,一个是老师类,一个是学生类。首先选中项目名称,鼠标右键 => “add new……”
点击 “add new……” 之后,出现如下界面
选择 “choose” 出现如下界面。
注意:在 Qt 中新建类时,要选择新建类的父类。
很显然,在当前项目中还没有什么类适合做新类的父类,同时新的类也不是一个 “窗口” 或者 “控件”。这种情况一般选择 QObject 作为基类。
这样做的好处是:这个新类的对象可以搭配 Qt 的对象树机制。便于对象的正确释放。
选择 “下一步”,出现如下界面
对于 “学生类” 以上述同样的方式进行添加,添加完成之后,项目目录新增文件如下
在 teacher.h 中声明信号函数
在 studio.h 中声明槽函数
在 widget.h 中实例化 “老师类对象” 和 “学生类对象”
在 studio.cpp 中实现槽函数
在 widget.cpp 中连接自定义信号和槽
运行结果如下图
示例3:老师点击 “按钮” 触发学生上课
运行结果如下图
2 -> 带参数的信号和槽
Qt 的信号和槽也支持带有参数,同时也可以支持重载。
此处要求,信号函数的参数列表要和对应连接的槽函数参数列表一致。
此时信号触发,调用到槽函数时,信号函数中的实参就能够被传递到槽函数的形参中。
通过这样的机制,就可以让信号给槽传递数据了。
示例1:重载信号槽
1. 在 “widget.h” 头文件中声明重载的信号函数以及重载的槽函数
2. 在 “Widget.cpp” 文件实现重载槽函数以及连接信号和槽
注意:在定义函数指针时要指明函数指针的作用域
3. 执行结果如下图
示例2:信号槽参数列表匹配规则
1. 在 “widget.h” 头文件中声明信号和槽函数
2. 在 “widget.cpp” 文件中实现槽函数以及连接信号和槽
其实信号的参数个数可以多于槽函数的参数个数,但是槽的参数个数不能多于信号的参数个数。
但是在实际开发中最好保持参数个数也能匹配一致。
示例3:
1. 在 “widget.h” 头文件中声明信号和槽函数
2. 在 “widget.cpp”文件中实现槽函数以及连接信号和槽
3 -> 小结
一、基本语法规范
1. 自定义信号
-
必须声明在类的
signals:
区域 -
返回类型必须为
void
,只需声明无需实现(Qt自动生成) -
支持参数传递和重载
-
通过
emit
关键字触发(实际是空宏,但建议显式使用)
signals:
void mySignal(int value); // 声明
2. 自定义槽
-
可声明在
public slots:
或普通public:
区域 -
需完整实现函数逻辑,返回类型为
void
-
支持参数传递和重载
public slots:
void mySlot(int data); // 声明+实现
二、参数传递规则
-
核心机制
-
信号参数自动传递给槽函数形参
-
参数数量兼容性:
-
槽函数参数数量 ≤ 信号参数数量(多余参数被忽略)
-
禁止槽参数数量 > 信号参数数量(编译错误)
-
-
参数类型必须严格匹配(如
int
不能隐式转QString
)
-
-
重载处理
-
需用
static_cast
明确指定函数指针类型:
-
// 重载信号连接
connect(sender, static_cast<void(SenderClass::*)(int)>(&SenderClass::overloadedSignal),
receiver, &ReceiverClass::slotForInt);
三、实战注意事项
1. 连接顺序
-
必须先
connect
再emit
信号,否则槽函数不会触发
connect(teacher, &Teacher::classBegin, student, &Student::enterClass); // 1. 连接
emit teacher->classBegin(); // 2. 触发信号
2. 对象生命周期
-
通过 对象树机制 自动管理内存(推荐继承
QObject
) -
典型错误:槽函数访问已销毁对象 → 崩溃
-
解决方案:
-
使用
QPointer
弱指针 -
显式调用
disconnect()
-
3. 参数设计建议
-
优先使用 一致参数列表(避免隐式截断)
-
跨线程传递时,参数类型需注册元类型(
qRegisterMetaType
)
感谢各位大佬支持!!!
互三啦!!!