QT信号和槽与自定义的信号和槽
1.概述
这篇文章介绍下QT信号和槽的入门知识,通过一个案例介绍如何创建信号和槽,并调用他们。
2.信号和槽使用
下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。
- 创建按钮
在widget.cpp文件中创建按钮代码如下
#include "mywidget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
// 第二种创建按钮方式
QPushButton *btn2 = new QPushButton("构造按钮",this);
- 使用信号和槽实现点击按钮关闭窗口
使用QObject类中的connect函数连接信号和槽,该函数需要4个参数- 参数1: 发送者,谁发送信号——btn2
- 参数2: 发送的是什么信号,信号用函数地址——&QPushButton::clicked
- 参数3: 接受者,谁来接受信号——this指的是当前窗口对象
- 参数4: 槽,接受者做出的动作——&QWidget::close
connect(btn2, &QPushButton::clicked, this, &QWidget::close);
3.如何查看QT提供的信号和槽函数
在使用connect连接信号和槽的时候,第一个参数发送者是btn2按钮对象,属于QPushButton类。
如何查看系统提供的信号?
第二个参数需要知道发送什么信号,这个时候怎么知道QPushButton提供了哪些信号那,这就需要查看QT帮助文档。
首先在编辑器中点击HELP
打开帮助文档,输入QPush查看QPushButton
中提供的内容没有Signal
信号。
接着查看QPushButton
父类
在父类中看到有Signals
信号,点击它,跳转到信号介绍位置。
在信号介绍中给出了所有的信号,我们选择第一个就是我们示例中的点击信号。在使用这个信号函数时候一定要用地址引用方式调用它,就是在调用前加上&
符号。
connect(btn2, &QPushButton::clicked, this, &QWidget::close);
如何查看系统提供的槽?
查看方法和上面查看信号一样,我们是关闭窗口,窗口的类是QWidge
,查看它的槽中提供了close()
函数。
connect(btn2, &QPushButton::clicked, this, &QWidget::close);
3.自定义信号和槽功能
上面介绍的是使用QT提供的信号和槽,下面通过一个实例介绍如何自定义自己的信号和槽的功能。
示例功能描述
老师类发出一个下课的信号,学生类的槽执行请客吃饭
- 新建项目
首先新建一个QWidge
类型项目,然后在项目名称上右键,新建clss文件,名称输入
Teacher
。然后再新建另一个class文件,名称输入Student
。
2. 创建信号
在teacher.h
文件中创建信号, 信号只需要定义不需要实现。
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
/* 自定义信号,写到signals中
* 返回值是void,只需要声明不需要实现
* 可以有参数,可以重载
*/
void hungry();
};
#endif // TEACHER_H
- 创造槽
在student.h
文件中创建槽函数,槽函数声明后需要在student.cpp
文件中实现功能。
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
/* 早起QT版本,必须写到public slots, 高级版本可以写到public或者全局中
* 返回值void, 需要声明并且实现
* 可以有参数,可以重载
*/
void treat();
};
#endif // STUDENT_H
在student.cpp
文件中实现功能
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug() << "执行槽函数,请客吃饭";
}
- 连接信号和槽
在QWidget.h
文件中创建Teacher和Student类对象,创建一个触发下课的函数。
#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和Student类对象
Teacher *tc;
Student *st;
private:
Ui::Widget *ui;
// 创建一个触发下课的函数
void classIsDown();
};
#endif // WIDGET_H
在QWidget.cpp
文件中实现信号和槽的功能
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 1.创建对象
this->tc = new Teacher(this);
this->st = new Student(this);
// 2.连接信号和槽
connect(tc, &Teacher::hungry, st, &Student::treat);
// 3.调用触发下课函数
classIsDown();
}
//4.下课函数使用emit发送信号
void Widget::classIsDown()
{
emit tc->hungry();
}
Widget::~Widget()
{
delete ui;
}
4.信号和槽函数重载
当我们自定义信号和槽函数时,他们可以通过参数进行重载,实现更多的功能。当使用重载时,调用的时候需要使用函数指针指向函数地址,确认调用哪个重载的函数。
继续使用上面的示例,在Teacher和Student类中添加重载的信号和槽
- 添加重载的信号
在teacher.h文件中新增void hungry(QString foodName);
有参的信号
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
/* 自定义信号,写到signals中
* 返回值是void,只需要声明不需要实现
* 可以有参数,可以重载
*/
void hungry();
// 信号参数重载
void hungry(QString foodName);
};
#endif // TEACHER_H
- 添加重载的槽
在student.h文件中添加void treat(QString foodName);
槽函数
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
/* 早起QT版本,必须写到public slots, 高级版本可以写到public或者全局中
* 返回值void, 需要声明并且实现
* 可以有参数,可以重载
*/
void treat();
// 槽参数重载
void treat(QString foodName);
};
#endif // STUDENT_H
在student.cpp文件中实现槽函数功能
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug() << "执行槽函数,请客吃饭";
}
void Student::treat(QString foodName)
{
qDebug() << "执行参数重载的槽函数,吃" << foodName.toUtf8().data();
}
- 调用重载的信号和槽函数
在widget.cpp文件中通过connect()函数调用信号和槽之前需要先指明调用的是有参的信号和槽函数,方法如下
// 调用有参的信号和槽
// 1.声明一个函数指针,指向函数地址
void(Teacher::*teacherSignal) (QString) = &Teacher::hungry;
void(Student::*studentSlot)(QString) = &Student::treat;
// 2.连接信号和槽
connect(tc, teacherSignal, st, studentSlot);
完整代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 1.创建对象
this->tc = new Teacher(this);
this->st = new Student(this);
// 2.连接信号和槽
// connect(tc, &Teacher::hungry, st, &Student::treat);
// 3.调用触发下课函数
// classIsDown();
// 调用有参的信号和槽
// 1.声明一个函数指针,指向函数地址
void(Teacher::*teacherSignal) (QString) = &Teacher::hungry;
void(Student::*studentSlot)(QString) = &Student::treat;
// 2.连接信号和槽
connect(tc, teacherSignal, st, studentSlot);
// 3.调用触发下课函数
classIsDown();
}
//4.下课函数使用emit发送信号
void Widget::classIsDown()
{
// 调用无参信号
// emit tc->hungry();
// 调用有参信号
emit tc->hungry("糖醋里脊");
}
Widget::~Widget()
{
delete ui;
}
5.信号连接信号
上面触发信号使用的是emit,如果我们想实现通过点击按钮来触发信号,那么可以采用普通的按钮发送信号控制槽函数,还可以采用信号连接信号实现。
// 点击按钮触发下课,第一种方式通过信号和槽实现。
QPushButton *btn = new QPushButton("下课",this);
this->resize(600,400);
// connect(btn, &QPushButton::clicked, this, &Widget::classIsDown);
// 点击按钮触发下课,第二种通过信号连接信号实现
void(Teacher::*teacherSignal2) (void) = &Teacher::hungry;
void(Student::*studentSlot2)(void) = &Student::treat;
connect(tc, teacherSignal2, st, studentSlot2);
// 通过一个按钮信号,链接到上面Teacher的信号,触发上面的信号和槽执行
// 当点击按钮时,按钮发送信号给teacher的信号,teacher信号被触发就会发送信号给student槽函数
connect(btn, &QPushButton::clicked, tc, teacherSignal2);
6.断开信号
使用disconnect函数断开信号,函数中的参数就是要断开链接connect里面的参数。
// 点击按钮触发下课,第二种通过信号连接信号实现
void(Teacher::*teacherSignal2) (void) = &Teacher::hungry;
void(Student::*studentSlot2)(void) = &Student::treat;
connect(tc, teacherSignal2, st, studentSlot2);
// 通过一个按钮信号,链接到上面Teacher的信号,触发上面的信号和槽执行
connect(btn, &QPushButton::clicked, tc, teacherSignal2);
// 断开信号
disconnect(tc, teacherSignal2, st, studentSlot2);
7.扩展
- QT4版本信号和槽写法
// QT4版本信号和槽
connect(tc,SIGNAL(hungry()), st, SLOT(treat()));