QT C++(信号与槽函数,自定义信号和槽函数)

文章目录

  • [1. QT信号与槽函数](#1. QT信号与槽函数)
  • [2. QT自定义信号和槽函数](#2. QT自定义信号和槽函数)

1. QT信号与槽函数

QT信号关键要素:

  1. 信号源:那个控件发送的信号
  2. 信号类型:用户进行不同的操作,就可能触发不同的信号。
    eg:点击按钮,移动鼠标等
  3. 信号处理方式:使用槽函数(slot)将信号与对应的信号处理函数关联起来(回调函数)

在QT中使用connect函数关联信号和信号处理函数(槽函数),这个函数是QObject类(基类)的静态成员函数

connect函数原型

cpp 复制代码
 static QMetaObject::Connection connect(const QObject *sender, const char *signal,
                        const QObject *receiver, const char *member, Qt::ConnectionType type= Qt::AutoConnection);
  • sender:当前信号是那个控件发送的(信号源)
  • singal:信号的类型,发送的是那种信号
  • receiver+member:信号如何处理
    • receiver:那个对象负责处理(控件)
    • member:这个对象怎么处理(函数)
  • type:有默认值,一般不填写

QT信号也是QT对象,内部提供一些成员函数,使用时需要注意发送信号和相应的控件符合。

各种控件的信号可以看QT文档

上述的函数声明,是旧版本的QT,旧版本的QT给信号参数传参需要搭配一个SIGNAL宏

给槽函数传参需要搭配一个SLOT宏connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&QWidget::close));

eg:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton*button=new QPushButton(this);
    button->setText("关闭");
    button->move(200,200);
    //点击关闭信号,this指的Widget,通过Widget来响应这个信号,&QWidget::close是QT内置的槽函数,负责控件关闭
    connect(button,&QPushButton::clicked,this,&QWidget::close);
}

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

2. QT自定义信号和槽函数

自定义槽函数:

方式一:手动定义函数

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,&Widget::handerClick);
}

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

void Widget::handerClick()
{
    //按下按钮,设置窗口标题
    this->setWindowTitle("按钮按下");
    qDebug()<<this->windowTitle();
}

方法二:通过ui界面生成槽函数

这个窗口就是QPushButton控件提供的所有信号

此时这个函数自动会绑定这个按钮的信号(通过函数名称来绑定,函数名为on+按钮的objectname+信号名称)egon_myButton_clicked,当函数名符合上述规则,QT会对响应控件的信号自动进行绑定(connectSlotsByName函数)

自定义信号:实际开发中比较少,QT内置信号基本已经覆盖控件所有操作,自定义信号一般需要程序员手动发送(emit关键字)

QT信号本质上也是函数(特殊函数,只有函数声明,并且将其声明成QT信号即可,QT编译自动生成这个信号函数)

信号函数的返回值为void,有无参数都可以。

eg:

cpp 复制代码
//.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();

private slots:
    void on_myButton_clicked();

private:
    Ui::Widget *ui;

//自定义信号,QT扩展的关键字,在qmake扫描带这个关键字后会生成具体代码
signals:
    void mySignals();
public:
    void handMySignals();
};
#endif // WIDGET_H

//.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);
    //关联自定义信号
    connect(this,&Widget::mySignals,this,&Widget::handMySignals);
    //初始化时发送自定义信号
    emit mySignals();
}

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

void Widget::handMySignals()
{
    this->setWindowTitle("自定义信号");
}

带参数的信号和槽函数

当信号带有参数时,槽的参数必须和信号一致,此时发射信号时就可以给这个信号函数传递参数,与之对应的参数就会被传递给槽函数

cpp 复制代码
//.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 //Q_OBJECT宏:在QT中让某个类能够使用信号槽机制,必须要在类最开始的地方声明这个宏。

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

//自定义信号,QT扩展的关键字,在qmake扫描带这个关键字后会生成具体代码
signals:
    void mySignals(const QString&);
public:
    void handMySignals(const QString&);
};
#endif // WIDGET_H

//.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);

    //关联自定义信号
    connect(this,&Widget::mySignals,this,&Widget::handMySignals);
    //初始化时发送自定义信号
    emit mySignals("带参自定义信号");
}

Widget::~Widget()
{
    delete ui;
}
void Widget::handMySignals(const QString&text)
{
    this->setWindowTitle(text);
}

注意:当信号函数参数个数超过了槽函数参数个数,代码可以正常运行,信号多余的参数槽函数接受不到。反之报错

这里这样设计的原因是:信号与槽函数绑定不是一对一的,一个槽函数可能绑定多个信号,如果严格要求信号函数和槽函数参数一致,那么同一个槽函数有些信号无法绑定。使用这样的规则,信号和槽的绑定更加灵活,这样更多的信号就可以绑定到这个槽函数了。

Q_OBJECT宏:在QT中让某个类能够使用信号槽机制,必须要在类最开始的地方声明这个宏。

QT信号和槽机制的优点:

  1. 解耦合:触发用户的控件和处理用户的操作逻辑解耦合
  2. 一个信号可以绑定多个槽函数,一个槽函数也可以绑定多个信号(多对多,关联表)

此外可以使用disconnect函数断开信号和槽函数的连接

eg:

cpp 复制代码
void Widget::on_pushButton_clicked()
{
    this->setWindowTitle("修改窗口标题");
}

void Widget::on_pushButton_2_clicked()
{
    //断开原来按钮的槽函数
    disconnect(ui->pushButton,&QPushButton::clicked,this,&Widget::on_pushButton_clicked);
    qDebug()<<"重新绑定槽函数";
    //重新绑定信号槽
    connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handclick);
}

void Widget::handclick()
{
    this->setWindowTitle("重新修改窗口标题");
}

此外,在定义槽函数时也可以使用lambda表达式,其本质就是匿名函数,常常用于回调函数

eg:

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton*button=new QPushButton(this);
    button->setText("按钮");
    int* times=new int(1); //这里必须new 因为这是在构造函数中connect的,设计变量声明周期问题,new出的变量必须手动释放,变相提高了声明周期,使得connect函数捕获times指针解引用不会报错
    //lambda作为回调函数
    connect(button,&QPushButton::clicked,this,[=](){
        qDebug()<<"lambda回调函数";
        //点击按钮移动按钮
        button->move(10*(*times),10*(*times));
        *times+=1;
    });
    emit signals1();
    emit signals2();

}
相关推荐
Ysjt | 深2 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__2 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
Microsoft Word3 小时前
c++基础语法
开发语言·c++·算法
一只小小汤圆3 小时前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
legend_jz3 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
嘿BRE4 小时前
【C++】几个基本容器的模拟实现(string,vector,list,stack,queue,priority_queue)
c++
ö Constancy4 小时前
c++ 笔记
开发语言·c++
fengbizhe4 小时前
笔试-笔记2
c++·笔记
徐霞客3205 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt