一、信号槽的概念
类似于一些其它的编程语言或框架中的回调机制,信号槽是Qt基于C 语法新增的特性,使用起来非常方便,可以完成不同对象之间的通信。
信号槽的使用需要有以下两个条件:
- 通信的对象必须**继承自QObject类**,**QObject是Qt所有内置类型的基类**。
- 类中要有**Q_OBJECT宏**
二、函数原型
信号槽需要连接后才能触发,因此信号槽的**核心是连接函数,**连接函数是一个静态成员函数。
参数1:**发射者**,发射者是一个对象,此对象发射信号函数,**作为信号槽的触发条件。**
参数2:**信号函数**,参数1中的发射者发射出的信号函数,**作为信号槽的触发条件**。**需要使用 SIGNAL()包裹函数名称**
参数3:**接收者**,接收者是一个对象,此对象执行槽函数,**作为信号槽的执行结果**。
参数4:**槽函数**,参数3中接收者要执行的槽函数,**作为信号槽的执行结果。需要使用SLOT() 包裹函数名称。**
接收者绑定了发射者的信号函数,一旦发射者发射信号函数,接收者就执行槽函数。
三、连接方式
为了方便讲解,依次使用三种方式进行信号槽的连接。 - 自带信号 → 自带槽- 自带信号 → 自定义槽- 自定义信号 → 槽
3.1 自带信号 → 自带槽
这种方式是最简单的一种连接方式,因为信号函数和槽函数Qt都内置了,只需要程序员从文档中找到对应函数连接即可。
【例子】点击按钮,关闭窗口。
分析:先找因果关系的四个参数。
参数1:发射者,按钮对象
参数2:信号函数,点击
参数3:接收者,窗口对象
参数4:槽函数,关闭
mywidget.h
代码语言:javascript复制#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QPushButton>
#include <QWidget>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = nullptr);
~MyWidget();
private:
QPushButton *btn;
};
#endif // MYWIDGET_H
mywidget.cpp
代码语言:javascript复制#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(400,400);
// 实例一个按钮对象
btn = new QPushButton("自带信号,自带槽演示", this);
btn->move(100,100);
// 连接槽和函数
// 完成点击按钮关闭当前窗口
// 标准写法
connect(btn, SIGNAL(clicked()), this, SLOT(close()));
}
MyWidget::~MyWidget()
{
}
main.cpp
代码语言:javascript复制#include "mywidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWidget w;
w.show();
return a.exec();
}
3.2 自带信号 → 自定义槽
在实际的开发中,Qt不可能内置所有的函数,特别是槽函数,更多的情况是需要用户自定义一个槽函数来实现特定的功能,这种方式也是最常见的一种信号槽连接方式。
需要注意的是,槽函数是一种特殊的成员函数,实现槽函数的方式与普通成员函数类似。
注意:一定要先链接再触发信号 不然你虽然触发了信号但是接收者没有进行链接就触发不了槽函数
【例子】点击按钮,向右下方移动窗口并输出当前的窗口坐标。
参数1:按钮对象
参数2:clicked
参数3:窗口对象
参数4:自定义槽函数
dialog.h
代码语言:javascript复制#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
#include <QDebug>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton *btn;
private slots: // 私有槽函数
// 声明自定义槽函数
void mySlot();
};
#endif // DIALOG_H
dialog.cpp
代码语言:javascript复制#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(400,400);
btn = new QPushButton("向右下方移动",this);
btn->setGeometry(100,100,100,100);
// 连接信号槽
// 参数1:按钮对象 btn
// 参数2:clicked
// 参数3:窗口对象 this
// 参数4:自定义槽函数 mySlot
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));//类内通过this指针找到w,
第三个参数为什么是this因为自定义信号槽函数属于Dialog类而这个类只有一个对象就是w,
类内想要调w就必须用this
}
//法一:手写 法二:再定义中鼠标中点击重构
void Dialog::mySlot()//类内声明类外定义必须加作用域限定符
{
// 先获得当前窗口的坐标
int x = this->x();
int y = this->y();
// 增加后移动
move(x 10,y 10);
// 输出当前坐标
qDebug() << x 10 << "," << y 10;
}
Dialog::~Dialog()
{
}
3.3 自定义信号 → 槽
这种做法主要用于后期一些稍微复杂的场景,现在讲解无法使用合适案例演示,因此讲解的过程中并不是最优解,属于强行使用。
【例子】点击按钮,关闭窗口。
之前的思路:
现在的思路:
现在的思路需要有两个信号槽的连接,在自定义槽函数中要手动发射一个自定义信号函数,信号函数是一种非常特殊的函数,信号函数只有声明,没有定义;信号函数没有权限。
首先按钮与窗口进行链接connect 再点击按钮 按钮发射一个信号 由于两者绑定所以窗口会收到这个信号并触发槽函数,然后再去链接connect窗口与窗口本身就是自己链接自己 上一个触发的槽函数里面是一个自定义信号 然后发射这个自定义信号 窗口接受 并执行相应的槽函数
dialog.h
代码语言:javascript复制#ifndef DIALOG_H
#define DIALOG_H
#include <QLineEdit>
#include <QPushButton>
#include <QWidget>
class Dialog : public QWidget
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = nullptr);
private slots:
void mySlot(); // 自定义槽
void mySlot1();
signals:
void mySignal(); // 自定义信号
private:
QPushButton *btn;
QLineEdit *txt;
};
#endif // DIALOG_H
dialog.cpp
代码语言:javascript复制#include "dialog.h"
Dialog::Dialog(QWidget *parent) : QWidget(parent)
{
// 设置窗口大小
setFixedSize(600,400);
// 实例化一个QLineEdit对象
txt = new QLineEdit(this);
txt->setGeometry(260,100,170,50);
// 实例化一个按钮对象
btn = new QPushButton("自定义槽和信号操作",this);
// 设置位置和大小
btn->setGeometry(100,100,150,50);
// 连接信号和槽函数
connect(btn, SIGNAL(clicked()), this, SLOT(mySlot()));
// 给窗体连接自定义信号和自带槽函数
connect(this, SIGNAL(mySignal()), this, SLOT(mySlot1()));
}
void Dialog::mySlot()
{
// 手动触发自定义信号
emit mySignal();
}
void Dialog::mySlot1()
{
txt->setText("触发了自定义信号和槽函数");
}
【小结】
信号槽是个较新的概念,需要花点时间细细品味,细嚼慢咽,然后在理解的基础上运用。