深入理解Qt信号和槽机制、信号和槽中的Lambda表达式

xiaoxiao2021-04-18  77

转载地址:https://blog.csdn.net/qq_40194498/article/details/79647356

对于事件处理,MFC中使用的是消息映射机制,Qt使用的是信号和槽机制,在我看来,Qt的信号和槽比MFC功能更强大,也更灵活。1、信号和槽的简单介绍: 一般格式:

connect(Sender,SIGNAL(signal),Receiver,SLOT(slot)); connect(信号发送者,信号,信号接受者,槽函数); 12

做个很简单的比喻:运动比赛,裁判员鸣枪,运动员起跑,信号发送者是裁判,信号是枪声;信号接受者是运动员,槽函数(对信号做出的相应)是起跑。

所有的QObject都可以使用信号和槽机制,而Qt中的大部分类都是继承于QObject,SIGNAL()和()SLOT()是Qt定义的两个宏,他们返回其参数的C语言风格的字符串(const *char,信号加前缀2,槽加前缀1),因此下面的两个语句是相同的: connect(Object2,SIGNAL(clicked()),Object3,SLOT(functionA())); connect(Object2,”2clicked()”,Object3,”1functionA()”); 例如:

QTimer *mytimer = new QTimer(this); mytimer->start(1000); connect(mytimer,"2timeout()",this,"1my_slot()"); 123

需要注意的是:不论是信号还是槽函数,在SIGNAL()和SLOT()中使用时,参数只能包含变量类型,不能包含变量名

2、信号和槽的变化:

//一个信号可以与另一个信号相连 connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal2)); //同一个信号可以与多个槽相连,此时调用槽的顺序是随机的 connect(Object1,SIGNAL(signal1),Object2,SLOT(slot1)); connect(Object1,SIGNAL(signal1),Object3,SLOT(slot2)); //同一个槽也可以响应多个信号 connect(Object1,SIGNAL(signal1),Object3,SLOT(slot1)); connect(Object2,SIGNAL(signal2),Object3,SLOT(slot1)); //连接也可以被移除,当然,这种情况很少见,因为对象被删除时,Qt会自动移除该对象相关的所有连接 disconnect(Sender,SIGNAL(signal),Receiver,SLOT(slot)); //要把信号和槽(或信号)成功连接,被连接的两者,其参数必须有相同的顺序和类型,这里有个例外是,如果信号的参数比它连接的槽的参数多,多余的参数会被简单的忽略掉 connect(Object1,SIGNAL(signal(int,const QString&)),Object2,SIGNAL(signal(int,const QString&)); 123456789101112

3、Qt5中信号和槽的扩展3.1、 C++11中增加了兰布达表达式(Lambda),在Qt5的信号和槽中,也可以使用兰布达表达式: 由于用了C++11的特性,需要在.pro文件中添加:CONFIG += C++11

QTimer *mytimer = new QTimer(this); mytimer->start(1000); //Lambda表达式对应的信号必须是函数指针形式 connect (mytimer ,&QTimer::timeout, [=]() { //dosomething,信号发出之后,需要做的事情 } ); 12345678

方括号内代表可用的实体(变量、控件等),多个可用逗号隔开,方括号内还可以放一些好用的运算符:

[=] () {} Lambda函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量),此时Lambda表达式中,实体默认为只读的,在大括号内不能进行修改,如果想修改,可以用mutable修饰,如 [=]() mutable

[&] () {} Lambda函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)

[this] () {} 函数体内可以使用Lambda所在类中的所有成员变量注意:尽量使用 = 而不使用 & ,以免造成内存问题

3.2、

QPushButton *b = new QPushButton(this); connect(&b,&QPushButton::pressed,this,&MainWidget::close); //Qt5引入了信号槽的新语法:使用函数指针能够获得编译期的类型检查。 //Qt4版本信号槽 connect(b,SIGNAL(pressed()),this,SLOT(close())); 123456

3.3、 lambda表达式的返回值问题可移步我的另一篇博客:https://blog.csdn.net/qq_40194498/article/details/798615264、信号和槽的注意事项

信号和槽的效率是非常高的,不过同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失,追求高效率的实时系统中,应尽量少用;信号和槽机制和普通函数的调用相同,如果使用不当的话,在程序执行时也有可能产生死循环。函数指针不能作为信号或槽的参数信号和槽不能有缺省参数当信号的发送者为定时器时,尽量不要把connect函数放在if、while等可能会导致信号槽阻塞的代码段里面。我做过这样一个事情:启动程序时启动定时器,用一个If语句判断输入是否合法,判断通过则调用发送者为定时器的connect函数,结果本该一分钟触发一次的槽函数在一秒内被连续触发了十几次;当子线程中需要使用信号槽机制时,必须在子线程头文件中加宏Q_OBJECT,当我们创建继承于QThread的子线程时,这个宏并不会自动添加。手动添加之后,构建项目可能会报错:undefined reference to ‘vtable for’,此时我们需要将子线程类从项目中移除(不要从磁盘上删除),然后重新添加,QtCreator就会重新解析此类,再编译就不再会出现上述错误.待续

--------------------- 作者:52_赫兹的鲸 来源: 原文:https://blog.csdn.net/qq_40194498/article/details/79647356?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

转载请注明原文地址: https://www.6miu.com/read-4819893.html

最新回复(0)