当前位置: 首页 > news >正文

QT —— 信号和槽(槽函数)

QT —— 信号和槽

  • 信号和槽
    • 信号(Signal)
    • 槽(Slot)
    • 声明方式
    • 工作原理
    • 连接方式
      • 1. 传统连接方式(Qt4风格)
      • 2. 新式连接方式(Qt5风格)
  • 区分槽函数和信号
  • 通过QtCreator生成信号槽代码
    • 自动生成槽函数
    • 显式连接的优势
    • 命名约定自动连接的局限性
    • 最佳实践建议
    • 结论

我们之前对QT,有了一个大致的了解,如果还有对QT这个概念还不清楚的小伙伴可以点击这里:

https://blog.csdn.net/qq_67693066/category_12625974.html

今天我们来了解一下QT当中的信号和槽,这个主要就是和connect函数有关系:

信号和槽

其实我们之前已经简单使用过了信号和槽的功能,就是我们用其他方式实现HelloWorld的时候:
在这里插入图片描述
connect函数是最好的例子,这里的connect函数的意思是:mybutton会发出&QPushButton中的clicked信号,然后这个信号会被this(也就是Widget接收),接收之后,处理方法为handler

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);mybutton = new QPushButton(this); //创建一个按钮mybutton->move(200,300); //修改按钮位置mybutton->setText("这是一个按钮"); connect(mybutton,&QPushButton::clicked,this,&Widget::handler);
}void Widget::handler()
{if(mybutton->text() == "这是一个按钮"){mybutton->setText("你点击了按钮");}else if(mybutton->text() == "你点击了按钮"){mybutton->setText("这是一个按钮");}
}Widget::~Widget()
{delete ui;
}

其实可以把connect函数里面的参数可以分类一下:

在这里插入图片描述

这样的话我们就一目了然了,下面我们来介绍一下信号和槽的概念:

信号和槽(Signals & Slots)是Qt框架的核心特性,用于对象间的通信。它是一种强大的观察者模式实现,比传统的回调函数更灵活、更安全。

信号(Signal)

  • 由对象在特定事件发生时发出的通知
  • 只需声明,不需要实现(由moc自动生成)
  • 可以带有参数,用于传递数据

槽(Slot)

  • 响应特定信号的函数
  • 需要实现,可以是普通成员函数
  • 可以接收信号传递的参数

声明方式

class MyClass : public QObject
{Q_OBJECT  // 必须包含这个宏public:explicit MyClass(QObject *parent = nullptr);signals:    // 信号声明区void valueChanged(int newValue);void operationCompleted();public slots:  // 槽函数声明区void setValue(int value);void doSomething();private slots:void internalHandler();
};

工作原理

  1. 当信号被发射(emit)时,所有连接到该信号的槽函数都会被调用
  2. 一个信号可以连接多个槽
  3. 多个信号可以连接到一个槽
  4. 信号可以连接到另一个信号(形成信号链)

连接方式

1. 传统连接方式(Qt4风格)

connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(setValue(int)));

2. 新式连接方式(Qt5风格)

connect(sender, &SenderClass::valueChanged, receiver, &ReceiverClass::setValue);

区分槽函数和信号

我们在写代码的时候要注意槽函数和信号,槽函数的标识像一把梳子,而信号则有像WiFi一样的符号
在这里插入图片描述

通过QtCreator生成信号槽代码

如果我们创建按钮是在ui界面上创建的,还有一种方式可以帮助我们隐式连接,我们进入ui,创建一个按钮,右击转到槽
在这里插入图片描述
选择对应的信号:
在这里插入图片描述
点击OK,会自动生成一个函数:
在这里插入图片描述

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->pushButton->setText("这是一个按钮");
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{if(ui->pushButton->text() == "这是一个按钮"){ui->pushButton->setText("你点击了按钮");}else if(ui->pushButton->text() == "你点击了按钮"){ui->pushButton->setText("这是一个按钮");}
}

这样和显示用connect是一样的效果:
在这里插入图片描述
在这里插入图片描述

自动生成槽函数

⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中:

1、以"on"开头,中间使用下划线连接起来;
2、"XXX"表示的是对象名(控件的 objectName 属性)。
3、"SSS"表示的是对应的信号。
如:"on_pushButton_clicked()",pushButton代表的是对象名,clicked是对应的信号。

在Qt开发中,信号和槽的连接方式主要有两种风格:基于命名约定的自动连接和显式的connect调用。虽然Qt支持通过特定命名规则自动连接信号槽,但我更推荐开发者使用显式connect的方式,原因如下:

显式连接的优势

  1. 代码可读性更强

    • 通过connect语句可以一目了然地看到对象间的通信关系
    • 避免隐藏在命名规则中的"魔法连接",降低理解成本
  2. 编译时检查(Qt5新语法)

    • 使用新式语法connect(sender, &Sender::signal, receiver, &Receiver::slot)
    • 编译器会检查信号和槽的签名是否匹配,提前发现错误
  3. 减少隐式错误

    • 避免因拼写错误导致的连接失效
    • 防止因重构改名而破坏原有连接
  4. 灵活性更高

    • 可以方便地使用Lambda表达式
    • 支持动态连接/断开
    • 能够指定不同的连接类型(如跨线程的QueuedConnection)

命名约定自动连接的局限性

虽然Qt提供了on_对象名_信号名这种命名约定来自动连接信号槽(通过QMetaObject::connectSlotsByName),但这种方式的缺点包括:

  1. 隐式连接不够直观

    • 连接关系分散在代码各处,难以追踪
    • 新开发者可能不了解这种"魔法"行为
  2. 重构风险

    • 修改UI对象名称时容易破坏现有连接
    • 缺乏编译时检查,运行时才能发现错误
  3. 灵活性受限

    • 难以实现复杂的连接逻辑
    • 不支持Lambda表达式等现代C++特性

最佳实践建议

  1. 优先使用显式connect

    // 推荐 - Qt5新式语法
    connect(ui->pushButton, &QPushButton::clicked, this, &MyWidget::handleButtonClick);
    
  2. 对于简单UI逻辑,可适度使用Lambda

    connect(ui->pushButton, &QPushButton::clicked, [this](){// 处理点击逻辑
    });
    
  3. 避免完全依赖命名约定的自动连接

    • 即使使用UI设计器生成的代码,也应检查确认连接关系
  4. 保持一致性

    • 在项目中统一采用显式连接风格
    • 在代码审查中检查连接方式

结论

虽然Qt框架提供了多种连接信号槽的方式,但显式使用connect函数能够带来更好的代码可维护性和更少的运行时错误。特别是在大型项目或团队协作中,显式声明对象间的通信关系远比依赖隐式命名约定更为可靠。

相关文章:

  • 【1】CICD持续集成-docker本地搭建gitlab代码仓库社区版
  • 用cursor三个小时复刻高德地图的足迹地图
  • 突发重磅消息!!!CVE项目将被取消?
  • MySQL的MVCC机制详解
  • SQL刷题日志(day2)
  • 【AI】IDEA 集成 AI 工具的背景与意义
  • 一个基于Django的写字楼管理系统实现方案
  • C/C++---头文件保护机制
  • Spring Boot整合Kafka的详细步骤
  • 局域网内Docker镜像共享方法
  • 【李宏毅深度学习——分类模型的PyTorch架构】Homework 2:Phoneme Classification
  • Docker镜像迁移指南:从Windows构建到Ubuntu运行
  • halcon模板匹配(五)find_shape_model_clutter
  • Jetpack Compose 跨组件通信:全面指南与最佳实践
  • 数据库勒索病毒威胁升级:企业数据安全防线如何用安当RDM组件重构
  • 光刻机研发与市场现状分析报告
  • 关于k8s的部署
  • shell 编程之正则表达式与文本处理器
  • 【Web API系列】Web Shared Storage API之WorkletSharedStorage深度解析与实践指南
  • 下篇:《高阶排序算法:分治思想与性能突破》
  • cms建站是什么/网络营销是指
  • 进网站备案时间/旺道seo网站优化大师
  • 建筑网站汇总/广点通广告投放平台登录
  • 哪个网站可以做视频片头/互动营销案例100
  • 学做烤制食品的网站/关键词优化排名用什么软件比较好
  • 电影网站建设规划书/怎么提高关键词搜索排名