槽的本质:对信号响应的函数。
信号函数和槽函数通常位于某个类中,和普通的成员函数相⽐,它们的特别之处在于:
信号函数⽤ signals 关键字修饰,槽函数⽤ public slots、protected slots 或者 private slots 修饰。signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字,专⻔⽤来指明信号函数和槽数;信号函数只需要声明,不需要定义(实现),⽽槽函数需要定义(实现)。
信号和槽的使用
在 Qt 中,QObject 类提供了⼀个静态成员函数 connect() ,该函数专⻔⽤来关联指定的信号函数和槽函数。
connect函数原型:
connect (const QObject *sender,const char * signal ,const QObject * receiver ,const char * method ,Qt::ConnectionType type = Qt::AutoConnection )
参数说明:
• sender:信号的发送者;• signal:发送的信号(信号函数);• receiver:信号的接收者;• method:接收信号的槽函数;• type:⽤于指定关联⽅式,默认的关联⽅式为 Qt::AutoConnection,通常不需要⼿动设定。
自动生成槽函数
通过在UI中创建控件,鼠标右键(找到 【转到槽】-> 【选择对应的信号】)来快速生成槽函数。
该方法对应的操作如下:
(1) 在 "widget.h" 头⽂件中⾃动添加槽函数的声明;
说明:
⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中:
1、以 " on " 开头,中间使⽤下划线连接起来;2、" XXX " 表⽰的是对象名(控件的 objectName 属性)。3、" SSS " 表⽰的是对应的信号。如:" on_pushButton_clicked() " ,pushButton 代表的是对象名,clicked 是对应的信号。
(2) 在 "widget.cpp" 中⾃动⽣成槽函数定义.
自定义信号和槽
1、⾃定义信号函数书写规范
(1)⾃定义信号函数必须写到 "signals" 下;(2)返回值为 void,只需要声明,不需要实现;(3)可以有参数,也可以发⽣重载;
2、⾃定义槽函数书写规范
(1)早期的 Qt 版本要求槽函数必须写到 "public slots" 下,但是现在⾼级版本的 Qt 允许写到类的 "public" 作⽤域中或者全局下;(2)返回值为 void,需要声明,也需要实现;(3)可以有参数,可以发⽣重载;
带参数的信号和槽
Qt 的信号和槽也⽀持带有参数, 同时也可以⽀持重载.
此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表⼀致.
此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中.
代码示例
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void mySignal(const QString& text,const QString& text2);
public:
void handleSignal(const QString& text);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
};
#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);
connect(this,&Widget::mySignal,this,&Widget::handleSignal);
// // 发射出自定义的信号
// //发送信号的操作,也可以在任意合适的代码中,不一定非得在构造函数里
// emit mySignal();
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleSignal(const QString& text)
{
// this->setWindowTitle("处理自定义信号");
this->setWindowTitle(text);
}
void Widget::on_pushButton_clicked()
{
// 发射出自定义的信号
//发送信号的操作,也可以在任意合适的代码中,不一定非得在构造函数里
// emit mySignal();
emit mySignal("把标题设置为标题1","");
}
void Widget::on_pushButton_2_clicked()
{
emit mySignal("把标题设置为标题2","");
}
结果演示:
信号与槽的连接方式
一对一
一对多
多对一
代码演示(一对多,多对一)
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void mySignal1();
void mySignal2();
void mySignal3();
public slots:
void mySlot1();
void mySlot2();
void mySlot3();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this,&Widget::mySignal1,this,&Widget::mySlot1);
connect(this,&Widget::mySignal1,this,&Widget::mySlot2);
connect(this,&Widget::mySignal2,this,&Widget::mySlot1);
connect(this,&Widget::mySignal2,this,&Widget::mySlot3);
}
Widget::~Widget()
{
delete ui;
}
void Widget::mySlot1()
{
qDebug()<<"mySlot1";
}
void Widget::mySlot2()
{
qDebug()<<"mySlot2";
}
void Widget::mySlot3()
{
qDebug()<<"mySlot3";
}
信号与槽的断开
使⽤ disconnect 即可完成断开.
disconnect 的⽤法和 connect 基本⼀致
代码演示
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handleClick();
void handleClick2();
//private slots:
// void on_pushButton_clicked();
private slots:
void on_pushButton_2_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.hpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handleClick()
{
this->setWindowTitle("修改窗口的标题");
qDebug()<<"handleClick";
}
void Widget::handleClick2()
{
this->setWindowTitle("修改窗口的标题2");
qDebug()<<"handleClick2";
}
//void Widget::on_pushButton_clicked()
//{
//}
void Widget::on_pushButton_2_clicked()
{
//先断开 pushButton 原来的信号槽
disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);
// connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick2);
}
使用lambda定义槽函数
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button=new QPushButton(this);
button->setText("按钮");
button->move(200,200);
connect(button,&QPushButton::clicked,this,[=](){
qDebug()<<"lambda 被执行了!";
button->move(300,300);
this->move(100,100);
});
}
Widget::~Widget()
{
delete ui;
}