Qt 详谈信号与槽(二)

目录

1. ⾃定义信号和槽

1.1 基本语法

1.2 带参数的信号和槽

2. 信号与槽的连接⽅式

2.1 ⼀对⼀

2.2 ⼀对多

2.3 多对⼀

3. 信号和槽的其他说明

3.1 信号与槽的断开

3.2 Qt4 版本信号与槽的连接

3.3 使⽤ Lambda 表达式定义槽函数

3.4 信号与槽的优缺点


1. ⾃定义信号和槽

1.1 基本语法

在 Qt 中,允许⾃定义信号的发送⽅以及接收⽅,即可以⾃定义信号函数和槽函数。但是对于⾃定义的信号函数和槽函数有⼀定的书写规范。

1、⾃定义信号函数书写规范

(1)⾃定义信号函数必须写到 "signals" 下;

(2)返回值为 void,只需要声明,不需要实现;

(3)可以有参数,也可以发⽣重载;

2、⾃定义槽函数书写规范

(1)早期的 Qt 版本要求槽函数必须写到 "public slots" 下,但是现在⾼级版本的 Qt 允许写到类的"public" 作⽤域中或者全局下;

(2)返回值为 void,需要声明,也需要实现;

(3)可以有参数,可以发⽣重载;

3、发送信号

使⽤ "emit" 关键字发送信号 。"emit" 是⼀个空的宏。"emit" 其实是可选的,没有什么含义,只是为了提醒开发⼈员。

⽰例1:

1、在 widget.h 中声明⾃定义的信号和槽,如图所⽰;

2、在 widget.cpp 中实现槽函数,并且关联信号和槽

注意:图中的 ① 和 ② 的顺序不能颠倒。
原因是, ⾸先关联信号和槽,⼀旦检测到信号发射之后就会⽴⻢执⾏关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应.

⽰例2:当⽼师说 "上课了",学⽣们就 "回到座位,开始学习"。

1、在源⽂件中新建两个类,⼀个是⽼师类,⼀个是学⽣类;⾸先选中项⽬名称,⿏标右键 -----> "add new..."

点击 "add new..." 之后,出现如下界⾯:

选择 "choose" 出现如下界⾯.

注意:
在 Qt 中新建类时, 要选择新建类的⽗类.
显然,当前项⽬中还没啥类适合做新类的⽗类, 同时新的类也不是⼀个 "窗⼝" 或者 "控件". 这种情况⼀般选择 QObject 作为基类.
这样做的好处是这个新类的对象可以搭配 Qt 的对象树机制. 便于对象的正确释放.

选择 "下⼀步",出现如下界⾯ :

对于 "学⽣类" 以上述同样的⽅式进⾏添加,添加完成之后,项⽬⽬录新增⽂件如下:

在 teacher.h 中声明信号函数:

在 student.h 中声明槽函数:

在 widget.h 中实例化 "⽼师类对象" 和 "学⽣类对象";

在 student.cpp 中实现槽函数:

在 widget.cpp 中连接⾃定义信号和槽;

运⾏结果如下图⽰:

⽰例3:⽼师点击 "按钮" 触发学⽣上课;

运⾏结果如下图⽰:

1.2 带参数的信号和槽

Qt 的信号和槽也⽀持带有参数, 同时也可以⽀持重载.

此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表⼀致.

此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中.

通过这样的机制, 就可以让信号给槽传递数据了.

⽰例1:重载信号槽

(1)在 "widget.h" 头⽂件中声明重载的信号函数以及重载的槽函数;如下图所⽰:

(2)在 "Widget.cpp" ⽂件实现重载槽函数以及连接信号和槽。

注意:在定义函数指针时要指明函数指针的作⽤域。

(3)执⾏结果如下图所⽰:

⽰例2:信号槽参数列表匹配规则

1、在 "widget.h" 头⽂件中声明信号和槽函数;

2、在 "widget.cpp" ⽂件中实现槽函数以及连接信号和槽

其实信号的参数个数可以多于槽函数的参数个数,但是槽的参数个数不能多于信号参数个数.
但是实际开发中最好还是保持参数个数也能匹配⼀致.

⽰例3:

1、在 "widget.h" 头⽂件中声明信号和槽函数;

2、在 "widget.cpp" ⽂件中实现槽函数以及连接信号和槽;

2. 信号与槽的连接⽅式

2.1 ⼀对⼀

主要有两种形式,分别是:⼀个信号连接⼀个槽 和 ⼀个信号连接⼀个信号。

(1)⼀个信号连接⼀个槽

⽰例:

1、在 "widget.h" 中声明信号和槽以及信号发射函数;

2、在 "widget.cpp" 中实现槽函数,信号发射函数以及连接信号和槽;

(2)⼀个信号连接另⼀个信号

⽰例:

在上述⽰例的基础上,在 "widget.cpp" ⽂件中添加如下代码:

2.2 ⼀对多

⼀个信号连接多个槽

⽰例:

(1)在 "widget.h" 头⽂件中声明⼀个信号和三个槽;

(2)在 "widget.cpp" ⽂件中实现槽函数以及连接信号和槽;

2.3 多对⼀

多个信号连接⼀个槽函数

⽰例:

(1)在 "widget.h" 头⽂件中声明两个信号以及⼀个槽;

(2)在 "widget.cpp" ⽂件中实现槽函数以及连接信号和槽;

3. 信号和槽的其他说明

3.1 信号与槽的断开

使⽤ disconnect 即可完成断开.

disconnect 的⽤法和 connect 基本⼀致.

⽰例:

3.2 Qt4 版本信号与槽的连接

Qt4 中的 connect ⽤法和 Qt5 相⽐是更复杂的. 需要搭配 SIGNAL SLOT 宏来完成.

⽽且缺少必要的函数类型的检查. 使代码更容易出错.

⽰例:

(1)在 "widget.h" 头⽂件中声明信号和槽

(2)在 "widget.cpp" ⽂件中实现槽函数以及连接信号与槽;

Qt4 版本信号与槽连接的优缺点:

优点:参数直观;

缺点:参数类型不做检测;

3.3 使⽤ Lambda 表达式定义槽函数

Qt5 在 Qt4 的基础上提⾼了信号与槽的灵活性,允许使⽤任意函数作为槽函数。

但如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式 来达到这个⽬的。

Lambda表达式 是 C++11 增加的特性。C++11 中的 Lambda表达式 ⽤于定义并创建匿名的函数对象,以简化编程⼯作。

Lambda表达式 的语法格式如下:

[ capture ] ( params ) opt -> ret { 
 Function body; 
};
capture 捕获列表
params 参数表
opt 函数选项
ret 返回值类型
Function body 函数体

1、局部变量引⼊⽅式 [ ]

[ ] : 标识⼀个 Lambda表达式 的开始。不可省略。

说明:

由于使⽤引⽤⽅式捕获对象会有局部变量释放了⽽Lambda函数还没有被调⽤的情况。如果执⾏Lambda函数,那么引⽤传递⽅式捕获进来的局部变量的值不可预知。所以绝⼤多数场合使⽤的形式为: [=] () { }

早期版本的 Qt,若要使⽤Lambda表达式,要在 ".pro" ⽂件中添加: CONFIG += C++11因为 Lambda表达式 是 C++11 标准提出的。Qt5 以上的版本⽆需⼿动添加,在新建项⽬时会⾃动添加。

3.4 信号与槽的优缺点

优点: 松散耦合

信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了⾃⼰,Qt的信号槽机制保证了信号与槽函数的调⽤。⽀持信号槽机制的类或者⽗类必须继承于 QObject类。

缺点: 效率较低

与回调函数相⽐,信号和槽稍微慢⼀些,因为它们提供了更⾼的灵活性,尽管在实际应⽤程序中差别不⼤。通过信号调⽤的槽函数⽐直接调⽤的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调⽤速度对性能要求不是⾮常⾼的场景是可以忽略的,是可以满⾜绝⼤部分场景。

⼀个客⼾端程序中, 最慢的环节往往是 "⼈".
假设本⾝基于回调的⽅式是 10us, 使⽤信号槽的⽅式是 100us. 对于使⽤程序的⼈来说, 是感
知不到的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值