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

QT ------ 信号和槽

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

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

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

信号和槽

其实我们之前已经简单使用过了信号和槽的功能,就是我们用其他方式实现HelloWorld的时候:

connect函数是最好的例子,这里的connect函数的意思是:mybutton会发出&QPushButton中的clicked信号,然后这个信号会被this(也就是Widget接收),接收之后,处理方法为handler

cpp 复制代码
#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)

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

声明方式

cpp 复制代码
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风格)

cpp 复制代码
connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(setValue(int)));

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

cpp 复制代码
connect(sender, &SenderClass::valueChanged, receiver, &ReceiverClass::setValue);

区分槽函数和信号

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

通过QtCreator生成信号槽代码

如果我们创建按钮是在ui界面上创建的,还有一种方式可以帮助我们隐式连接,我们进入ui,创建一个按钮,右击转到槽

选择对应的信号:

点击OK,会自动生成一个函数:

cpp 复制代码
#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

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

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

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

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

结论

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

相关推荐
wjs20249 分钟前
DOM CDATA
开发语言
Tingjct10 分钟前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
猷咪37 分钟前
C++基础
开发语言·c++
IT·小灰灰38 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧40 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q40 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳040 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾40 分钟前
php 对接deepseek
android·开发语言·php
2601_9498683644 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计1 小时前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识