Qt教程 — 2.2 深入了解Qt信号与槽

目录

1 信号与槽简介

2  如何在UI 文件里连接信号与槽

3  Qt 信号与槽机制

3.1 QObject::connect() 信号与槽实现函数

方式一:通过UI Designer会自动生成QObject::connect()

方式二:手动方式编辑QObject::connect()

3.2 信号与槽的注意事项

(1) 一个信号可以连接多个槽

(2) 多个信号可以连接同一个槽

(3) 一个信号可以连接另外一个信号

(4)  断开一切与 myObject 连接的信号或槽

(5)   断开所有连接到特定信号的东西

(6) 与指定的接收者断开连接

4 如何在项目中创建信号和槽

4.1 如何在项目里创建信号

4.2 如何在项目里创建槽

4.3 如何在项目中连接信号与槽


1 信号与槽简介

Qt的信号与槽机制是Qt框架中实现对象之间通信的一种方式,属于Qt的核心特性之一。在这个机制中,信号(signal)是由对象在发生了某种状态改变时发出的消息,槽(slot)是用来被信号触发的函数。

  • 信号(Signal):是由对象发出的一种特殊的公共成员函数,但它不是由程序员直接调用的,而是由Qt自己调用以响应某个事件。信号一旦发生,就会通知那些与之连接的槽函数。
  • 槽(Slot):可以是普通的成员函数,用于响应信号。槽可以与任何信号连接,而与信号发生的对象的类型无关。当与之相连的信号被触发时,槽函数就会被自动调用。

这种机制相比于传统的回调函数有很多优势,最主要的是它能够确保程序的松耦合和高级的事件处理能力。通过信号和槽,Qt开发者可以轻松地在不同的组件之间进行消息传递,从而使得应用程序架构更为清晰和灵活。

2  如何在UI 文件里连接信号与槽

在文章2.2节已进行了详细的描述:Qt教程 — 2.1 如何使用Qt Designer 开发UI程序-CSDN博客

3  Qt 信号与槽机制

3.1 QObject::connect() 信号与槽实现函数

信号与槽关联是用 QObject::connect() 函数实现的,其基本格式是:

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

  • connect() :是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用时可以省略前面的限定符。
  • sender: 是发射信号的对象的名称。
  • signal():是信号名称。信号可以看做是特殊的函数, 需要带括号,有参数时还需要指明参。
  • receiver:是接收信号的对象名称。
  • slot() :是槽函数的名称,需要带括号,有参数时还需要指明参数。
方式一:通过UI Designer会自动生成QObject::connect()

通过第2节的方法设置好通过按钮关闭主窗口的信号和槽后,运行后在mainwindow.app —> ui_mainwindow.h头文件中会自动生成QObject::connect() 函数,修改程序内容ui_mainwindow.h头文件也会自动更新。

方式二:手动方式编辑QObject::connect()

在mainwindows.cpp下,直接将方式一生成的代码复制到会报错,原因是pushButton和this->MainWindows找不到位置,pushButton是命名空间ui下的成员函数,this->MainWindows就在MainWindows命名空间下,写成this即可,具体代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // QObject::connect(pushButton, SIGNAL(clicked()), this->MainWindow, SLOT(close()));
    
    QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close()));
    
}

代码修改位置如下: 

3.2 信号与槽的注意事项

(1) 一个信号可以连接多个槽

当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。

connect(pushButton, SIGNAL(clicked()), this, SLOT(hide());
connect(pushButton, SIGNAL(clicked()), this, SLOT(close());

这是当一个对象 pushButton 的被单击时,窗体有两个槽进行响应,一个 hide()用于隐藏主窗体,一个 close() 用于关闭主窗体。 这里只是举个例子,实际上当执行 close()后, hide()这个槽已经没有什么意义了, 因为已经程序退出了, 但是实际它有执行,因为它连接在 close()的前面。

(2) 多个信号可以连接同一个槽

多个信号可以连接同一个槽,例如设置3个pushButton 到设计的窗体里,同时也让它按3.1小节里的第一种方法连接信号与槽,把三个按钮的 clicked()信号对应连接到close()、hide()、lower()槽函数。

编译后可以在 ui_mainwindow.h 这个文件里自动生成如下的信号槽连接语句。

QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(close()));
QObject::connect(pushButton_2, SIGNAL(clicked()), MainWindow, SLOT(hide()));
QObject::connect(pushButton_3, SIGNAL(clicked()), MainWindow, SLOT(lower()));
(3) 一个信号可以连接另外一个信号

这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。

connect(pushButton,SIGNAL(objectNameChanged(QString)),this,SIGNAL(windowTitelChanged(QString)));

  • pushButton是信号的发送者,指的是一个按钮对象(假定是QPushButton类型的)。
  • SIGNAL(objectNameChanged(QString))是发送者发出的信号,这里指的是pushButtonobjectNameChanged信号,该信号在对象的objectName属性改变时发出。objectNameChanged(QString)传递一个QString参数,表示新的对象名称。
  • this指的是信号的接收者,在这个上下文中,通常指的是包含这行代码的对象(可能是一个窗口或者其他Qt对象)。
  • SIGNAL(windowTitleChanged(QString))是接收者将要发出的信号。这意味着当pushButtonobjectName属性发生变化时,不是调用一个槽函数,而是直接发出了一个新的信号windowTitleChanged(QString),同样传递一个QString参数,这个信号需要在接收者这边定义。
(4)  断开一切与 myObject 连接的信号或槽

disconnect(myObject, 0, 0, 0);

(5)   断开所有连接到特定信号的东西

disconnect(myObject, SIGNAL(mySignal()), 0, 0);

(6) 与指定的接收者断开连接

disconnect(myObject, 0, myReceiver, 0);

4 如何在项目中创建信号和槽

4.1 如何在项目里创建信号

(1) 新建项目命名为 03_signal_slot_example, 同时取消勾选*ui 文件, 其他步骤不变。

(2) 由于信号只需声明, 无需定义。 所以我们只需要在 mianwindow.h 里声明信号即可。 代码如下,如下图黑色加粗部分代码就是创建的信号。这里创建一个 void pushButtonTextChanged();信号。完整代码如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    
signals:
    void PushButtonTextChanged();
};
#endif // MAINWINDOW_H

4.2 如何在项目里创建槽

创建槽的方法也很简单, 也是直接在 mianwindow.h 里直接声明槽,在 mianwindow.cpp 里
实现槽的定义,就是C++创建函数的流程。

槽有以下特点:

  • 槽可以是任何成员函数、普通全局函数、静态函数。
  • 槽函数和信号的参数和返回值要一致。

(1) 在mianwindow.h 声明信号 void pushButtonTextChanged();所以我们声明的槽函数必须是无返回值类型 void,和无需参数,同时还声明一个按钮点击的槽。此外还声明一个 QPushButton 对象 pushButton。完整代码如下: 

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
// 引入 QPushButton文件
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    
signals:
    void PushButtonTextChanged();
    
public slots:
    // 声明一个槽函数
    void changeButtonText();
    // 声明按钮点击的槽函数
    void pushButtonClicked();

private:
    // 声明一个对象 pushButton
    QPushButton *pushButton;    
};
#endif // MAINWINDOW_H

(2) 在 mainwindow.cpp 里 实 现 声 明 的 槽 函 数 void changeButtonText(); 和 void pushButtonClicked(); 同时还实例化了 pushButton 对象。同时设置按钮的文字大小、边界和颜色参数。

4.3 如何在项目中连接信号与槽

在2.3节介绍了项目中连接信号与槽的函数。在 mainwindow.cpp 中补充信号槽连接的代码。 mainwindow.cpp完整代码如下:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // 设置MainWindow尺寸
    this->resize(800,600);
    pushButton = new QPushButton(this);
    // 设置按钮文字
    pushButton->setText("我是一个按钮");
    // 设置按钮位置和尺寸
    pushButton->setGeometry(340, 50, 120, 60);
    // 设置按钮文字颜色
    pushButton->setStyleSheet("QPushButton { color: red; }");

    // 信号与槽连接
    connect(pushButton, SIGNAL(clicked()), this,SLOT(pushButtonClicked()));
    connect(this, SIGNAL(PushButtonTextChanged()), this, SLOT(changeButtonText()));
}

MainWindow::~MainWindow()
{
}

void MainWindow::pushButtonClicked()
{
    emit PushButtonTextChanged();
}

void MainWindow::changeButtonText()
{
    pushButton->setText("被点击了");
    // 设置按钮文字颜色
    pushButton->setStyleSheet("QPushButton { color: green; }");
}

最后实现的效果如下,点击前文字为红色,点击后为绿色。

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值