Qt信号与槽

自定义的信号与槽

自定义信号要写到signals下,只需要声明,不需要重载,返回值为void。

在早期版本,需要将槽函数写在public slots下,而在5.4之后,可以将槽函数写在public下或者写在全局下。需要声明与实现,返回void。

考虑下面的应用场景:下课后,同学感到饥饿,老师请客吃饭。

对于这个问题需要实现Student与Teacher两个实体类,均继承QObject基类以便析构。Student类有hungry这个信号,Teacher类有treat这个槽函数。Widget类中含有Student与Teacher两个类型的成员变量,含有classOver()成员方法。调用classOver()方法激活hungry信号,从而触发treat槽函数。

student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

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

signals:
    void hungry(); //hungry信号的声明,无需实现
};

#endif // STUDENT_H

student.cpp

#include "student.h"

Student::Student(QObject *parent)
    : QObject{parent}
{

}

teacher.h

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);
    void treat(); //treat槽的声明
signals:

};

#endif // TEACHER_H

teacher.cpp

#include "teacher.h"
#include <iostream>
#include <QDebug>

Teacher::Teacher(QObject *parent)
    : QObject{parent}
{

}

//treat槽的实现
void Teacher::treat(){
    std::cout << "eat something" << std::endl;
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <teacher.h>
#include <student.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    //含有两个成员变量
    Teacher *teacher;
    Student *student;

private:
    Ui::Widget *ui;
    void classOver();
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //初始化成员变量,将父节点设置为this便于析构
    this->teacher = new Teacher(this);
    this->student = new Student(this);

    //将信号与槽进行链接
    connect(this->student, &Student::hungry, this->teacher, &Teacher::treat);
    classOver();

}

Widget::~Widget()
{
    delete ui;
}

void Widget::classOver(){
    emit this->student->hungry();
}

程序运行后,执行classOver()函数,其中触发了hungry信号,执行treat槽函数,从而在控制台上输出eat something

信号与槽的重载

上一节的案例中,仅仅输出eat something。现在增加需求,考虑输出吃的食物的名称。

信号的参数个数可以多于槽的参数个数,但信号与槽的参数类型必须对应,这样可以保证槽能够正常接收到信号的参数。hungry()与treat()都是无参的,现在考虑对其进行重载,使它们均含有一个QString类型的参数代表学生想要吃的食物名称,对代码进行更改。

student.h中对hungry()进行重载

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

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

signals:

    void hungry();
    void hungry(QString foodName); //含参的信号

};

#endif // STUDENT_H

teacher.h对treat()进行重载

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);
    void treat();
    void treat(QString foodName); //含参的槽函数

signals:

};

#endif // TEACHER_H

teacher.cpp

新增的代码中,含有foodName.toUtf8().data()这个语句。如果直接输出QString变量,会多出两个引号,所以需要将其转为utf8类型的字节数据再转为char *类型进行输出。

#include "teacher.h"
#include <iostream>
#include <QDebug>

Teacher::Teacher(QObject *parent)
    : QObject{parent}
{

}

void Teacher::treat(){
    std::cout << "eat something" << std::endl;
}

//含参的treat()函数的实现
void Teacher::treat(QString foodName){
    qDebug() << "eat" << foodName.toUtf8().data() << '\n';
}

widget.cpp

connect语句中需要传递函数指针,由于函数已经进行过重载,上一个案例中使用的方法无法表示函数的地址,所以需要事先创建好两个函数指针,再将其传入。这里需要注意创建函数指针的语法。

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->teacher = new Teacher(this);
    this->student = new Student(this);

    //创建函数指针
    void(Student::*studentSignal)(QString) = &Student::hungry;
    void(Teacher::*teacherSlot)(QString) = &Teacher::treat;


    //将信号与槽相连。
    connect(this->student, studentSignal, this->teacher, teacherSlot);
    classOver();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::classOver(){
    emit this->student->hungry("宫保鸡丁");
}

程序运行后,执行classOver()函数,其中触发了hungry信号,执行treat槽函数,从而在控制台上输出eat 宫保鸡丁

信号连接信号

考虑下面的场景:点击按钮后学生感觉到饿,老师请客。

类似于信号连接槽,可以将信号与信号相连。将按钮点击信号连接到hungry,再将hungry连接到treat即可。

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->teacher = new Teacher(this);
    this->student = new Student(this);

    QPushButton *btn = new QPushButton("classOver", this);

    void(Student::*studentSignal)(void) = &Student::hungry;
    void(Teacher::*teacherSlot)(void) = &Teacher::treat;

    connect(btn, &QPushButton::clicked, this->student, studentSignal);
    connect(this->student, studentSignal, this->teacher, teacherSlot);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::classOver(){
    emit this->student->hungry("宫保鸡丁");
}

Qt4的信号与槽

可以按照如下的Qt4写法进行编写。优点:参数直观。缺点:编译期间不做参数类型检测,而是程序运行中提示错误(原理为字符串匹配)。

//本行代码就含有参数不匹配的错误,需要删除"QString"
connect(this->student, SIGNAL(hungry()), this->teacher, SLOT(treat(QString))); 

要注意的是,QT4写法只能将槽写在public slots中

#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

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

public slots:
    void treat();
    void treat(QString foodName); 

signals:

};

#endif // TEACHER_H

lambda表达式

C++11中的Lambda表达式用于创建匿名的函数对象

使用如下的代码声明一个Lambda表达式

[](){
	
};

使用如下的代码声明一个Lambda表达式并调用

[](){
	
}();

中括号内可以传递一些参数

  • 空。没有使用任何函数对象参数。
  • =。函数体内可以使用Lambda所在作用域范围内所有可见的局部变量(包含Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
  • &。函数体内可以使用Lambda所在作用域范围内所有可见的局部变量(包含Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
  • this。函数体内可以使用Lambda所在类中的成员变量。
  • a。将a按值进行传递。按值传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数时const的。要修改传递进来的a的拷贝,需要添加mutable修饰符。
  • &a。将a按引用进行传递。
  • a, &b。将a按值进行传递,b按引用进行传递。
  • =, &a, &b。a和b按引用进行传递,其余均按值传递。
  • &, a, b。a和b按值进行传递,其余均按引用传递。
    使用如下代码编写一个带有返回值的Lambda
int a = []() ->int {return 1000;}();

可以同时使用connect与Lambda来简化代码,这样写还可以省略connect语句的第三个参数。

    QPushButton *btn = new QPushButton("close", this);
    connect(btn, &QPushButton::clicked, [=](){
        this->close();
    });

断开连接

可以使用disconnect()函数断开信号与槽的连接,语法与connect()相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FengLing255

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值