一.信号和槽
1.信号(signal):用于在不同的对象之间传递消息。
当某个事件发生时,比如按钮被点击,它就会发出一个信号。这个信号没有特定目的,类似于广播,它只是通知其他对象发生了某个事件。
2.槽(slot):槽是与信号关联的函数,它用于处理信号。当信号被发射时,与之关联的槽函数会自动被调用。
信号和槽之间的联系是通过QObject::connect函数建立的。这个函数用于将一个信号与一个或多个槽函数连接起来,当信号被触发时,相应的槽函数就会被调用。
信号和槽的关联可以是多对多的关系,即一个信号可以连接多个槽函数,而多个信号也可以连接到同一个槽函数。
这就类似观察者模式:当发生了特定的事件,某一个操作就会被自动触发。
3.举例
开关 -> 被按下 -> 灯 -> 亮了
优点:松散耦合,信号发出端和接收端可以毫无关联,如果要关联就用connect函数。
connect (sender,signal,receiver,slot);
参数:信号发出者 信号 信号接收者 执行的任务(槽函数)
QPushButton *button = new QPushButton("关闭",this);
this->resize(600,400);
connect(button,&QPushButton::clicked,this,&Widget::close);
信号发出者:button 信号:clicked
信号接收者:this 执行的任务(槽函数): close
4.自定义信号与槽
步骤一:确定场景
老师饿了,学生请客。
步骤二:添加老师类和学生类
步骤三:在老师类中声明信号,在学生类中声明并实现槽函数
①在teacher.h中:void hungry ( );
信号:在signals作用域下写,返回值void,参数可以存在,仅声明不需要实现,可以重载。
②在student.h中:void treat ( );
槽函数:可以写到public或者全局,参数可以存在,需要声明并实现,可以重载。
③在student.cpp中:实现treat函数。
void Student::treat(){
qDbug()<<"请吃饭";
}
注意:需要包含QDebug头文件。
步骤四:创建对象并触发下课信号
①在widget.h中,写出学生类和老师类的头文件,声明学生和老师对象,声明触发信号的成员函数(public内):
Teacher *tea;
Student *stu;
void ClassOver();
②在widget.cpp中,创建学生和老师对象,定义触发信号的成员函数,并调用该函数:
this->tea=new Teacher(this);
this->stu=new Student(this);
connect(tea,&Teacher::hungry,stu,&Student::treat);
ClassOver();
//全局:
void Widget::ClassOver(){
emit tea->hungry();
}
步骤五:实现点击按钮,打印“请吃饭”
在上述代码基础上,再添加:
方式一:
connect(button,&QPushButton::clicked,this,&Widget::ClassOver);
方式二:(信号连接信号)
connect(button,&QPushButton::clicked,tea,&Teacher::hungry);
5.重载自定义信号与槽
步骤一:信号声明(带参数)
步骤二:槽函数声明及定义(带参数)
注意:ClassOver函数内容也要带上参数
步骤三:由于函数的重载,所以需要利用函数指针指向函数地址,然后再做连接:
void (Teacher:: *teachersignal) (QString) = &Teacher::hungry;
void (Student:: *studentslot) (QString) = &Student::treat;
connect(tea,teachersignal,stu,studentslot);
步骤四:实现点击按钮,打印“请吃饭 food”,添加上述步骤五方式一中的代码即可。
6.自定义信号槽注意事项:
①发送者与接收者需要是QObject的子类(槽函数全局,lambda除外)。
②槽函数是普通的成员函数,会受到public,private,protected的影响。
③任何成员函数、static函数、全局函数和lambda表达式都可以作为槽函数。
④使用emit在恰当位置发送信号,用connect函数连接信号和槽。
⑤槽函数的参数可以比信号少。
⑥槽可以被断开连接(disconnect),也可以被取消连接(当一个对象被delete则取消这个对象上的槽)。
二.Lambda表达式
C++11中的lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。
[capture](parameters)mutable -> return-type{statement}
[capture]:捕获列表,捕获的是那些到定义lambda为止时lambda所在作用范围内可见的局部变量。
(parameters):参数列表,与普通函数的参数列表一致。
mutable:可修改标识符,按值传递函数对象参数时(默认是仅读权限),加上mutable修饰符后,可以修改按值传递进来的拷贝。
return-type:返回值类型。
statement:函数体,内容跟普通函数一致。
注意:
① [ ] 是一个lambda的开始,不能省略。
空:没有使用任何函数对象参数
=:函数体内可以使用lambda所在作用范围内所有可见的局部变量,值传递
&:函数体内可以使用lambda所在作用范围内所有可见的局部变量,引用传递
a:将a按值进行传递
&a:将a按引用进行传递
this:函数体内可以使用lambda所在类中的成员变量
② ( ) 参数列表在不需要传参时可以省略。
③如果使用mutable,参数列表不能省略,即使参数为空;mutable修改的是拷贝而不是值本身。
④返回值类型如果不需要可省略。
⑤函数体内可以使用参数列表,也可以使用捕获列表。
1.通过lambda表达式打印内容
auto fun = [](){
qDebug()<<"lambda";
};
fun();
或者:
int c=12;
[=](){
qDebug()<<"lambda";
qDebug()<<c;
}();
2.测试参数列表和可修改标识符(如果无mutable,m=20 会报错)
int m=10;
auto fun=[m](int a,int b)mutable{
qDebug()<<"lambda";
m=20;
return a+b;
};
qDebug()<<fun(100,200);
qDebug()<<m;
打印结果:300 10
3.槽函数一般可用lambda表达式
connect(button,&QPushButton::clicked,this,[](){
qDebug()<<"lambda";
});