【Qt】信号和槽机制

这篇具有很好参考价值的文章主要介绍了【Qt】信号和槽机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、认识信号和槽

二、connect函数

三、自定义槽函数

四、自定义信号

五、带参数的信号和槽

六、信号和槽断开连接

七、信号和槽存在的意义

八、Lambda表达式定义槽函数


一、认识信号和槽

概述

在Qt中,用户和控件的每次交互过程称为一个事件。如"用户点击按钮"是一个事件,"用户关闭窗口"也是一个事件。每个事件都会发出一个信号,如用户点击按钮会发出"按钮被点击"的信号,用户关闭窗口会发出"窗口被关闭"的信号

Qt中的所有控件都具有接收信号的能力,⼀个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。如:按钮所在的窗口接收到"按钮被点击"的信号后,会做出"关闭自己"的响应动作;再如:输入框自己接收到"输入框被点击"的信号后,会做出"显示闪烁的光标,等待用户输入数据"的响应动作。在Qt中,对信号做出的响应动作就称之为槽

信号和槽是Qt特有的消息传输机制,它能将相互独立的控件关联起来。如:"按钮"和"窗口"本身是两个独立的控件,点击"按钮"并不会对"窗口"造成任何影响。通过信号和槽机制,可以将"按钮"和"窗口"关联起来,实现"点击按钮会使窗口关闭"的效果

信号的本质

信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时Qt对应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件

槽的本质

槽(Slot)就是对信号响应的函数。槽就是⼀个函数,与一般的C++函数是一样的,可以定义在类的任何位置(public、protected或private),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与信号关联,当信号被发射时,关联的槽函数被自动执行

说明

  • 信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,即信号函数;每个槽也可以用函数表示,即槽函数
  • 信号函数和槽函数通常位于某个类中,和普通的成员函数相比,它们的特别之处在于:

信号函数用signals关键字修饰,槽函数用public slots、protected slots或者private slots修饰(使用普通成员函数的方式修饰也可)。signals和slots是Qt在C++的基础上扩展的关键字,专门用来指明信号函数和槽函数;信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)

Q_OBJECT

若一个类要使用信号和槽机制,必须在类中添加Q_OBJECT这个宏

【Qt】信号和槽机制,Qt,qt

二、connect函数

在Qt中,QObject类提供了一个静态成员函数connect(),该函数专门用来关联指定的信号函数和槽
函数。QObject是Qt内置的父类,Qt中提供的很多类都是直接或者间接继承自QObject

Qt Assistant中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,通常不需要手动设定

但是C++不允许使用两个不同的指针类型相互赋值,使用const char*明显是不行的。因为Qt Assistant中的函数声明,是以前旧版本的Qt的connect函数的声明

在以前的版本中,给信号参数传参需要要搭配一个SIGNAL宏,给槽参数传参需要搭配一个SLOT宏。从Qt5开始,对上述写法进行了简化,给connect重载版本,第二个参数和第四个参数成了泛型函数,允许传入任意参数了

【Qt】信号和槽机制,Qt,qt

此时connect函数就带有了一定的参数检查的功能,若传入的第一个参数和第二个参数,或者第三个参数和第四个参数不匹配,代码出现编译错误。不匹配是指:2、4参数传入的函数指针,不是1、3参数的成员函数的指针

connect函数使用案例:点击按钮关闭窗口

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* btn = new QPushButton("按钮", this);
    btn->move(200, 200);
    connect(btn, &QPushButton::clicked, this, &QWidget::close);
}

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

三、自定义槽函数

  • 早期的Qt版本要求槽函数必须写到"public slots"下,但是现在高级版本的Qt允许写到类的"public"作用域中或者全局下
  • 返回值为void,需要声明,也需要实现
  • 可以有参数,可以发生重载

代码编写槽函数

widget.h: 

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void HandleClicked();//槽函数声明

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);
    QPushButton* btn = new QPushButton("按钮", this);
    btn->move(200, 200);
    connect(btn, &QPushButton::clicked, this, &Widget::HandleClicked);
}

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

//槽函数定义
void Widget::HandleClicked()
{
    setWindowTitle("按钮已按下");
}

ui创建槽函数

【Qt】信号和槽机制,Qt,qt

【Qt】信号和槽机制,Qt,qt

自动生成的槽函数的名字是on_pushButton_clicked,其中on是固定的,pushButton是ui中的objectName,clicked写明了是哪种信号。ui自动生成的槽函数不需要connect函数就能在触发信号时被回调。(ui_widget.h中调用了QMetaObject::connectSlotsByName,它会触发自动连接信号槽的规则)

四、自定义信号

自定义信号很少用到。因为在GUI中,用户的操作行为是可以穷举的,Qt内置的信号已经覆盖到了大部分可能的用户操作

  • 信号是一种特殊的函数,程序员只需写出函数声明,并告诉Qt,这是一个信号即可。这个函数的定义,是Qt在编译过程中,自动生成的(无法干预)
  • 信号函数的返回值必须是void,有没有参数都可以,也支持函数重载
  • 信号可以使用emit关键字进行发射(Qt5 emit不写也行)

【Qt】信号和槽机制,Qt,qt

五、带参数的信号和槽

信号和槽也可以带参数。发射信号时,就可以给信号函数传递实参,这个参数就会被传递到对应的槽函数中。信号和槽函数的参数类型必须一致,个数可以不一致,但是信号的参数个数必须大于槽函数的参数个数(当个数不一致时,就会按顺序拿到信号的前N个参数)

【Qt】信号和槽机制,Qt,qt

一个信号可以通过connect关联多个槽函数,一个槽函数也能被多个信号关联

六、信号和槽断开连接

使用disconnect断开信号槽的连接(主动断开往往是把信号重新绑定到另一个槽函数上)

widget.cpp:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    btn = new QPushButton("按钮", this);
    btn->move(200, 200);
    connect(btn, &QPushButton::clicked, this, &Widget::HandleClicked_1);

    QPushButton* changeBtn = new QPushButton("修改按钮功能", this);
    changeBtn->move(200, 400);
    connect(changeBtn, &QPushButton::clicked, this, &Widget::ChangeButtonRole);
}

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

void Widget::HandleClicked_1() { setWindowTitle("修改窗口标题1"); }

void Widget::HandleClicked_2() { setWindowTitle("修改窗口标题2"); }

void Widget::ChangeButtonRole()
{
    disconnect(btn, &QPushButton::clicked, this, &Widget::HandleClicked_1);
    connect(btn, &QPushButton::clicked, this, &Widget::HandleClicked_2);
    qDebug() << "修改成功";
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    void HandleClicked_1();
    void HandleClicked_2();
    void ChangeButtonRole();

private:
    Ui::Widget *ui;
    QPushButton* btn;
};
#endif // WIDGET_H

若这里没有disconnect,会使一个信号绑定两个槽函数,触发点击按钮,同时执行两个槽函数

七、信号和槽存在的意义

  • 解耦合:信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt的信号槽机制保证了信号与槽函数的调用。支持信号槽机制的类或者父类必须继承于QObject类
  • 实现"多对多"的效果:一个信号可以connect到多个槽函数上,一个槽函数也可以被多个信号connect(实际开发中,这种情况极少)

缺点

与回调函数相比,信号和槽稍微慢⼀些,因为它们提供了更高的灵活性,尽管在实际应用程序中差别不大。通过信号调用的槽函数比直接调用的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调用速度对性能要求不是非常高的场景是可以忽略的,是可以满足绝大部分场景
 

八、Lambda表达式定义槽函数

  • 注意被捕获变量的生命周期
  • 尽量传值捕获,传引用捕获可能会捕获到已经被释放的变量,造成程序崩溃
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
    setFixedSize(1000, 1000);

    QPushButton* button = new QPushButton("点击移动", this);
    button->move(400, 800);
    connect(button, &QPushButton::clicked, this, [=](){
        qDebug() << "Lambda";
        button->move(800, 800);
    });
}

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

上述代码传值捕获没问题,传引用捕获会崩溃。原因是button是局部变量(它指向的空间位于堆区,但其本身是一个局部变量的指针),构造函数结束后button变量即被销毁,造成程序崩溃文章来源地址https://www.toymoban.com/news/detail-836438.html

到了这里,关于【Qt】信号和槽机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT之信号和槽

    一、什么是信号和槽? 我们经常看到的功能,点击一个按钮实现窗口关闭。 这一过程发生了什么?是怎么实现的 按钮相当于一个信号,点击相当于发送一个信号,窗口是个接收者,关闭窗口是个槽函数 信号:各种事件 槽:响应信号的动作 当一个按钮(信号)被触发(发送

    2024年02月07日
    浏览(24)
  • 【Qt】信号和槽

     需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、Qt中的信号和槽 1、信号 2、槽 3、Q_OBJECT 二、Qt中的connect函数 三、自定义信号、自定义槽 1、自定义槽函数 1.1使

    2024年01月21日
    浏览(30)
  • 【QT】信号和槽(15)

    前面的内容说了很多不同的控件如何使用,今天来看下QT的核心, 信号与槽(Signals and slots) ! 简单理解一下,就是我们的信号与槽连接上了之后,发射一个信号给到槽,槽函数接收到了这个信号之后,槽函数会被调用。 1.python 3.7.8   可直接进入官网下载安装:Download Pyt

    2024年02月10日
    浏览(39)
  • 07.QT信号和槽-2

            在Qt中,允许⾃定义信号的发送⽅以及接收⽅,即可以⾃定义信号函数和槽函数。但是对于⾃定义的信号函数和槽函数有⼀定的书写规范。 1.1 自定义信号 (1)⾃定义信号函数必须写到\\\"signals\\\"下; (2)返回值为void,只需要声明,不需要实现; (3)可以有参数,

    2024年04月14日
    浏览(25)
  • Qt6.2教程——3.Qt信号和槽

    信号和槽是Qt中一个强大的特性,用于处理对象之间的通信。它们是一种事件处理机制,允许一个对象在某个事件发生时通知另一个对象。 定义 : 信号是一个QObject的成员函数,当某个特定事件发生时,它被自动调用。它可以与一个或多个槽关联。 声明 : 在Qt类的声明中,信号

    2024年02月10日
    浏览(35)
  • [Qt的学习日常]--信号和槽

    前言 作者 :小蜗牛向前冲 名言 :我可以接受失败,但我不能接受放弃   如果觉的博主的文章还不错的话,还请 点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习:什么是信号和槽,自定义槽函数和信号函数,信号和槽的传参,断开,

    2024年04月28日
    浏览(20)
  • 02 qt基本控件及信号和槽

    功能:显示一个字符串内容 主要接口函数 构造函数: 赋值运算符重载: 功能函数: 1)基本数据类型(int,float,double,char*)转换成字符串 number(long , int ) : QString number(int , int ) : QString number(uint , int ) : QString number(ulong , int ) : QString number(qlonglong , int ) : QString number(qulonglong , int

    2024年02月12日
    浏览(30)
  • Qt快速学习(一)--对象,信号和槽

    目录 1.Qt概述 1.1 什么是Qt 2.2 手动创建 2.3 pro文件 2.4 一个最简单的Qt应用程序        3 第一个Qt小程序 3.1 按钮的创建 3.2 对象模型(对象树)       3.3 Qt窗口坐标体系 4 信号和槽机制         4.1 系统自带的信号和槽 4.2 自定义信号和槽     4.3信号槽的拓展     

    2024年02月12日
    浏览(27)
  • 20221210 QT----信号和槽的使用

    什么是信号(signal) 以QPushButton为例: (1)按下按钮时,会触发一个mousePressEvent事件,此时会发出一个pressed信号; (2)松开按钮时,会触发一个mouseReleaseEvent事件,此时会发出released和clicked信号。 事件的种类有很多,不同的事件都对应着不同的信号,当事件发生时,对应

    2024年02月15日
    浏览(34)
  • qt信号和槽避免多次连接

    qt同一个信号和槽多次连接,则槽函数 会触发多次 (默认),可能不是我们想要的结果。 有3种方法可以解决这个问题: 因为初始化函数在在整个程序中只运行一次,所以这里面连接信号和槽,就能避免重复连接问题了。 Qt::UniqueConnection 的作用是:如果该信号以前没连接过

    2024年02月10日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包