转载地址:https://blog.csdn.net/qq_40194498/article/details/79647356
对于事件处理,MFC中使用的是消息映射机制,Qt使用的是信号和槽机制,在我看来,Qt的信号和槽比MFC功能更强大,也更灵活。
1、信号和槽的简单介绍:
一般格式:
connect(Sender,SIGNAL(signal),Receiver,SLOT(slot));
connect(信号发送者,信号,信号接受者,槽函数);
- 1
- 2
做个很简单的比喻:运动比赛,裁判员鸣枪,运动员起跑,信号发送者是裁判,信号是枪声;信号接受者是运动员,槽函数(对信号做出的相应)是起跑。
所有的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()");
- 1
- 2
- 3
需要注意的是:
不论是信号还是槽函数,在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&));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
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,信号发出之后,需要做的事情
}
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
方括号内代表可用的实体(变量、控件等),多个可用逗号隔开,方括号内还可以放一些好用的运算符:
[=] () {}
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()));
- 1
- 2
- 3
- 4
- 5
- 6
3.3、
lambda表达式的返回值问题可移步我的另一篇博客:
https://blog.csdn.net/qq_40194498/article/details/79861526
4、信号和槽的注意事项
- 信号和槽的效率是非常高的,不过同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失,追求高效率的实时系统中,应尽量少用;
- 信号和槽机制和普通函数的调用相同,如果使用不当的话,在程序执行时也有可能产生死循环。
- 函数指针不能作为信号或槽的参数
- 信号和槽不能有缺省参数
- 当信号的发送者为定时器时,尽量不要把connect函数放在if、while等可能会导致信号槽阻塞的代码段里面。我做过这样一个事情:启动程序时启动定时器,用一个If语句判断输入是否合法,判断通过则调用发送者为定时器的connect函数,结果本该一分钟触发一次的槽函数在一秒内被连续触发了十几次;
- 当子线程中需要使用信号槽机制时,必须在子线程头文件中加宏
Q_OBJECT
,当我们创建继承于QThread的子线程时,这个宏并不会自动添加。手动添加之后,构建项目可能会报错:undefined reference to ‘vtable for’
,此时我们需要将子线程类从项目中移除(不要从磁盘上删除),然后重新添加,QtCreator就会重新解析此类,再编译就不再会出现上述错误. - 待续
--------------------- 作者:52_赫兹的鲸 来源:CSDN 原文:https://blog.csdn.net/qq_40194498/article/details/79647356?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!