一、前言
记住,信号与槽本质都是返回类型为void的函数。
QT提供的信号与槽,是QT的核心功能之一。它们跟QT的GUI没有关系,所以编写没有GUI的QT应用程序也是可以使用QT的信号与槽的。值得注意的是,使用QT编写漂亮且模块化的应用程序必须要使用信号与槽。
只要用户编写的类继承QObject类,就能使用信号与槽的功能。QT的signal(信号)与slot(槽)本质就是一个函数,且不需要返回值,意识到这一点非常重要。从下图可以看到,Object1的signal1可以同步(触发)Object2的slot1与slot2。Object1的signal2可以同步(触发)Object4的slot1。所以,QT的信号与槽有利于程序的模块化。
请同学们务必学习豆子的博客上的《QT学习之路2(5)自定义信号槽》,才能看懂以下的内容。博客地址:https://www.devbean.net/2012/08/qt-study-road-2-custom-signal-slot/
我的QT版本:
QT工程:
链接:https://pan.baidu.com/s/1lqoq0XhUgE1De8Ok1FPTHQ
提取码:s6yp
二、新建一个QT控制台项目
2.1、New File or Project
2.2、Project Location
2.3、Define Build System
2.4、Kit Selection
2.5、Project Application
2.6、生成的项目
三、创建类
3.1、创建Newspaper类
3.2、创建Reader类
以同样的方式创建Reader类
四、编写代码
4.0、pro文件
QT创建的项目默认是C++11版本,目前大部分的C++教程都是使用C++14版本,所以我决定使用C++14版本。值得注意的是,C++版本越高并不代表越好,追求稳定才是硬道理。
4.1、newspaper.h
#ifndef NEWSPAPER_H
#define NEWSPAPER_H
#include <QObject>
class Newspaper : public QObject
{
Q_OBJECT
public:
explicit Newspaper(QObject *parent = nullptr);
Newspaper(const QString& name);
void send() const; /* 用于发送已有的信号 */
signals:
/* 1、信号就是一个一个函数名,信号不需要返回变量,所以都是void.
* 2、信号的函数不需要实现,因为QT的moc帮我们实现好了.
* 3、信号的内容是什么?其实就是函数的入口参数.
*/
void newPaper(const QString& name) const; /* 声明一个信号(newPaper) */
public slots:
private:
QString m_name;
};
#endif // NEWSPAPER_H
4.2、newspaper.cpp
#include "newspaper.h"
Newspaper::Newspaper(QObject *parent) : QObject(parent)
{
}
Newspaper::Newspaper(const QString& name):
m_name(name)
{
}
/* 该函数用于发送已经定义好的信号 */
void Newspaper::send() const
{
emit newPaper(m_name); //发送newPaper信号,该信号的内容是m_name
}
4.3、reader.h
#ifndef READER_H
#define READER_H
#include <QObject>
#include <QDebug>
class Reader : public QObject
{
Q_OBJECT
public:
explicit Reader(QObject *parent = nullptr);
signals:
public slots:
void receiveNewspaper(const QString& name) const;
};
#endif // READER_H
4.4、reader.cpp
#include "reader.h"
Reader::Reader(QObject *parent) : QObject(parent)
{
}
void Reader::receiveNewspaper(const QString& name) const
{
qDebug() << "Receives Newspaper: " << name;
}
4.5、main.cpp
#include <QCoreApplication>
#include "newspaper.h"
#include "reader.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Newspaper newspaper("Newspaper A"); /* 创建newspaper对象 */
Reader reader; /* 创建reader对象 */
/* 建立信号与槽 */
QObject::connect(&newspaper,&Newspaper::newPaper,
&reader, &Reader::receiveNewspaper);
newspaper.send(); /* 调用信号,并触发对应的槽 */
return a.exec();
}
五、Debug
编译,运行。控制台输出一条字符串。
返回上面的代码可以了解到,newspaper对象不具备打印字符串到控制台的功能,只有reader对象才能往控制台输出字符串。所以,上面的字符串肯定是reader对象得槽函数打印出来的。
六、用一个信号同步(触发)两个槽
上面的例子是1个信号同步一个槽,根据官方的介绍,1个信号可以同步多个槽的。所以,这里尝试增加多一个槽。
信号的代码不需要修改,所以newspaper.cpp与newspaper.h不用修改(Newspaper类不用修改)。槽的代码需要修改一下,因为要给reader增加一个类属性my_name。
6.1、reader.h
#ifndef READER_H
#define READER_H
#include <QObject>
#include <QDebug>
class Reader : public QObject
{
Q_OBJECT
public:
explicit Reader(QObject *parent = nullptr);
Reader(const QString& name); //增加一个构造函数
signals:
public slots:
void receiveNewspaper(const QString& name) const ;
private:
QString my_name; //增加名字
};
#endif // READER_H
6.2、reader.cpp
#include "reader.h"
Reader::Reader(QObject *parent) : QObject(parent)
{
}
Reader::Reader(const QString& name):
my_name(name)
{
}
void Reader::receiveNewspaper(const QString& name) const
{
qDebug() <<"I am" << this->my_name << "Receives Newspaper: " << name;
}
6.3、main.cpp
#include <QCoreApplication>
#include "newspaper.h"
#include "reader.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Newspaper newspaper("Newspaper A"); /* 创建newspaper对象 */
Reader reader_A("reader_A"); /* 创建reader_A对象 */
Reader reader_B("reader_B"); /* 创建reader_B对象 */
/* 建立信号与槽 */
QObject::connect(&newspaper,&Newspaper::newPaper,
&reader_A, &Reader::receiveNewspaper);
/* 建立信号与槽 */
QObject::connect(&newspaper,&Newspaper::newPaper,
&reader_B, &Reader::receiveNewspaper);
newspaper.send(); /* 调用信号,并触发对应的槽 */
return a.exec();
}