一、系统自带的信号和槽
1.connect函数
connect函数是建立信号发送者、信号、信号接收者、槽四者关系的函数。
connect(sender, signal, receiver, slot);
参数解释:
sender:信号发送者
signal:信号
receiver:信号接收者
slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
注意:1.默认情况下,他们死者没有关系,通过connect建立四者的关系。
2.信号和槽,本质都是函数。
3.connect里面的四个参数都是指针:
connect(btn,&QPushButton::clicked,this,&Widget::hide);
4.使用connect的时候保留&符号:1.可以提高代码可读性
2.自动提示
QPushButton *btn = new QPushButton("按钮1",this);
//关闭 this->close()
// 按钮
// 被点击
// 窗口
// 关闭
connect(btn,&QPushButton::clicked,this,&widget::close);
二、自定义信号和槽
1.自定义信号:
1.函数声明在类头文件的signals域下面
2.void类型的函数,没有返回值
3.可以有参数,也可以重载
4.只有声明,没有实现定义
5.触发信号 emit obj->sign(参数...)
2.自定义槽
1.函数声明在类头文件的public/private/protected slots域下面(qt4以前的版本)
2.qt5 就可以声明在类的任何位置,还可以是静态成员函数、全局函数、lambda表达式
3.void 类型的函数,没有返回值
4.可以有参数,也可以重载
5.不仅有声明,还得有实现
3.带参数的自定义信号和槽
声明函数的时候就带上参数就行,例如老师说他饿了,说要吃黄焖鸡,学生就请吃黄焖鸡
调用带参数的信号函数 emit pTeacher->hungry("黄焖鸡");
4.参数二义性问题
1.使用函数指针赋值,让编译器自动挑选符合类型的函数
2.使用static_cast 强制转换 ,让编译器自动挑选符合类型的函数
5.实用场景
场景:下课了,老师说他饿了,学生就请吃饭
信号发送者:老师
信号:老师饿了
信号接收者:学生
槽:请吃饭
创建多少个类:Teacher,Student
信号:hungry 1个 Teacher
槽:treat 1个 Student
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//老师和学生的两个对象创建
pTeacher = new Teacher(this);
pStudent = new Student(this);
//建立连接
// connect(pTeacher,&Teacher::hungry,pStudent,&Student::treat);
//老师说要吃黄焖鸡,学生就请吃黄焖鸡
//hungry多加一个参数,QString
//treat 也要一个参数,QString
//因为函数发生了重载,所以解决
/*
* 1 使用函数指针赋值,让编译器挑选符合类型的函数
* 2 使用static_cast 强制转换,也是让编译器自动挑选符合类型的函数
*/
// void (Teacher::*teacher_qString)(QString) = &Teacher::hungry;
// void (Student::*student_qString)(QString) = &Student::treat;
// connect(pTeacher,teacher_qString,pStudent,student_qString);
//使用static_cast 来转换无参的函数
connect(pTeacher,
static_cast<void (Teacher::*)()>(&Teacher::hungry),
pStudent,
static_cast<void (Student::*)()>(&Student::treat));
//下课了
this->classIsOver();
}
void Widget::classIsOver()
{
//出发老师饿了的信号
emit pTeacher->hungry();
//带参数的信号发射
emit pTeacher->hungry("黄焖鸡\r\n");
}
三、信号和槽的拓展
1.一个信号可以连接多个槽
一个信号建立了多个connect,那么当信号发射的时候,槽函数的调用顺序是随机的
2.一个槽可以连接多个信号
3.信号可以连接信号
connect(第一个信号发送者,第一个信号,第二个信号发送者,第二个信号)
信号可以连接信号
QPushButton *btn = new QPushButton("按钮1",this);
connect(btn,&QPushButton::clicked,
pTeacher,
static_cast<void (Teacher::*)()>(&Teacher::hungry));
4.信号可以断开连接:disconnect
connect参数怎么填,disconnect就怎么填
//信号可以断开连接
disconnect(pTeacher,teacher_qString,pStudent,student_qString);
5.信号和槽的参数关系
1.信号和槽函数的参数类型必须对应
2.信号和槽函数的参数个数不需要一致,信号函数参数个数>=槽函数参数个数
hungry(QString) -> treat() //ok
hungry(QString) -> treat(int) //编译出错
hungry(QString,int)-> treat(int) //编译出错
注意:必须同时满足以上两点。
四、Qt4版本的信号槽写法
1.使用规则
1.使用两个宏SIGNAL、SLOT
2.connect使用不一样,信号和槽函数声明差不多
3. connect(信号发送者,SIGNAL(函数原型) ,信号接收者,SLOT(函数原型))
2.好处与坏处
好处:没有重载二义性的问题
坏处:写错了,编译期间不会报错
3.SIGNAL和SLOT宏的原理
就是将后边的参数转成字符串 类似 #define toStr(arg) #arg -> "arg"、
推荐:使用Qt5以后的
五、QDebug
1.概念
QDeubg输出QString默认会转义
2.解决方法
1.将QString转成 char *
qDebug()<<"Student treat teacher with "<<what.toUtf8().data();
2. 使用qDebug().noquote()
qDebug().noquote()<<"Student treat teacher with "<<what;
六、Lambda表达式
1.格式
[capture](parameters) opt ->retType
{
……;
}
2.含义
1. [capture] 捕获外部局部变量的列表,值传递,直接填变量名 ,引用传递就使用&变量名
使用= 值传递捕获所有局部变量
使用& 应用传递捕获所有局部变量
有特殊的捕获方式的变量在后边另外指定
2.如果是值传递捕获进来的变量默认是const , 需要修改的话要使用 mutable选项
3.返回值类型可以省略,编译器自动计算返回值
4.以后都推荐使用 [=](){} 的形式