Qt编程_day02

信号和槽机制

信号:各种事件
槽:响应信号的动作
当某个事件发生后,如某个按钮被点击了以下,它就会发出一个被点击的信号(signal)
某个对象接收到这个信号之后,就会做一些相关的处理(称为槽Slot)
要想让一个对象接收到另一个对象发出的信号,这时候就需要建立连接(connect)

信号发送者
信号
信号接收者
槽:信号的处理动作
默认情况下,他们四者没有关系,通过connect建立四者的关系
connect(信号发送者,信号,信号接收者,槽)

自定义信号和槽

自定义信号:

1. 函数声明在类头文件的signals域下
2. void类型的函数,没有返回值
3. 可以有参数,也可以重载
4. 只有声明,没有实现
5. 触发信号:emit obj->sign(参数....)

自定义槽

1. 函数声明在类的任何位置,还可以是静态成员函数,全局函数,lambda表达式
2. void类型的函数,没有返回值
3. 可以有参数,也可以重载
4. 不仅有声明,还得有实现

场景一:下课了,老师说他饿了,学生就请吃饭
信号发送者:老师
信号:老师饿了
信号接收者:学生
槽:学生请老师吃饭
创建类:Teacher 和 Student
在这里插入图片描述在这里插入图片描述在这里插入图片描述接着点击下一步,完成就可以创建一个类。

信号:hungry 一个 Teacher
槽:treat 一个 Student
代码:
student.h

#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class student : public QObject
{
    Q_OBJECT
public:
    explicit student(QObject *parent = nullptr);
signals:
public slots:
    //自定义槽
    //1. 函数声明在类的任何位置,还可以是静态成员函数,全局函数,lambda表达式
    //2. void类型的函数,没有返回值
    //3. 可以有参数,也可以重载
    //4. 不仅有声明,还得有实现

    //学生请吃饭
    void treat();
};
#endif // STUDENT_H

teacher.h

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class teacher : public QObject
{
    Q_OBJECT
public:
    explicit teacher(QObject *parent = nullptr);

signals:
    //自定义信号
    //1. 函数声明在类头文件的signals域下
    //2. void类型的函数,没有返回值
    //3. 可以有参数,也可以重载
    //4. 只有声明,没有实现
    //5. 触发信号:emit obj->sign(参数....)
    void hungry();

public slots:
};

#endif // TEACHER_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "teacher.h"
#include "student.h"
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

   void classIsOver();
private:
    teacher *pTeacher;
    student *pStudent;
};

#endif // WIDGET_H

student.cpp

#include "student.h"
#include <QDebug>
student::student(QObject *parent) : QObject(parent)
{

}
void student::treat()
{
    qDebug()<<"Student treat teacher";
}

teacher.cpp

#include "teacher.h"

teacher::teacher(QObject *parent) : QObject(parent)
{

}

widget.cpp

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建pTeacher和pStudent两个对象,并放到对象树上
    pTeacher = new teacher(this);
    pStudent = new student(this);

    //建立连接
    connect(pTeacher,&teacher::hungry,pStudent,&student::treat);
    //下课
    this->classIsOver();
}

void Widget::classIsOver()
{
    //触发老师饿了的信号
    emit pTeacher->hungry();
}
Widget::~Widget()
{

}

场景二:下课了,老师说他饿了,要吃黄焖鸡,学生就请吃黄焖鸡
与场景一的唯一区别就是信号与槽是带参函数
在student.h中加入

void treat(QString what);

在teacher.h中加入

void hungry(QString whart);

在student.cpp中加入

void student::treat(QString what)
{
    qDebug()<<"student treat teacher eat "<<what<<endl;
}

widget.cpp

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建pTeacher和pStudent两个对象,并放到对象树上
    pTeacher = new teacher(this);
    pStudent = new student(this);

    //建立连接
    //connect(pTeacher,&teacher::hungry,pStudent,&student::treat);

    //因为hungry和treat发生了重载,所以在建立连接时信号和槽具有二义性
    //解决办法:
    //1.使用函数指针赋值,让编译器自动挑选符合类型的函数
    void (teacher::*teacher_qString)(QString) = &teacher::hungry;
    void (student::*student_qString)(QString) = &student::treat;

    connect(pTeacher,teacher_qString,pStudent,student_qString);

    //2.使用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("黄焖鸡");
}
Widget::~Widget()
{

}

信号和槽的拓展

  1. 一个信号可以连接多个槽
    一个信号可以建立多个connect,那么当信号发射时,槽函数的调用顺序是随机的
  2. 一个槽可以连接多个信号
  3. 信号可以连接信号
    connect(第一个信号发送者,第一个信号,第二个信号发送者,第二个信号)
  4. 信号可以断开连接,disconnect
    connect参数怎么填,disconnect就怎么填
  5. 信号和槽的参数关系,必须同时满足以下两点
    • 信号和槽函数的参数类型必须对应
    • 信号和槽函数的参数个数不需要一致,信号函数参数个数>=槽函数个数

lambda表达式

[capture] (parameters) opt -> retType
{
…;
}

[capture] 捕获外部局部变量的列表。有两种捕获方式,一是值传递,直接填变量名,例如[a,b,c…];另外一种是引用传递,&变量名,例如[&a,&b,&c…]
使用 = ,值传递捕获所有局部变量
使用 & ,引用传递捕获所有局部变量
有特殊的捕获方式的变量在后边另外指定,例如:[&.b…]表示除了b以外,全部的局部变量都采用引用传递;[=,&b…]表示除了b以外,全部的局部变量都采用值传递。

如果是值传递捕获进来的变量默认是const,需要修改的话要使用mutable选项。

返回值可以省略,编译器自动计算。

以后都推荐使用[=] () {} 的形式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值