Qt的信号与槽

目录

[1 信号与槽概述](#1 信号与槽概述)

[2 信号槽使用](#2 信号槽使用)

[2.1 connect](#2.1 connect)

[2.2 内置信号与槽函数](#2.2 内置信号与槽函数)

[2.3 自动生成信号与槽](#2.3 自动生成信号与槽)

[3 自定义信号与槽](#3 自定义信号与槽)

[3.1 槽函数](#3.1 槽函数)

[3.2 信号](#3.2 信号)

[3.3 信号和槽带有参数](#3.3 信号和槽带有参数)

[4 信号与槽的连接方式](#4 信号与槽的连接方式)

[4.1 一对一](#4.1 一对一)

[4.3 多对一](#4.3 多对一)

[4.3 多对一](#4.3 多对一)

[5 解除连接关系](#5 解除连接关系)

[5.1 disconnect](#5.1 disconnect)

[6 Lambda表达式](#6 Lambda表达式)

[7 信号与槽的优缺点](#7 信号与槽的优缺点)


1 信号与槽概述


(1)信号的本质

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

信号的本质就是事件 ,如:

  1. 按钮单击、双击
  2. 窗⼝刷新
  3. ⿏标移动、⿏标按下、⿏标释放
  4. 键盘输

信号的呈现形式就是函数, 也就是说某个事件产⽣了, Qt 框架就会调⽤某个对应的信号函数, 通知使⽤者。

(2)槽的本质

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

2 信号槽使用


在 Qt 中,QObject 类提供了⼀个静态成员函数 connect() ,该函数专⻔⽤来关联指定的信号函数和槽函数。

关于 QObject:

QObject 是 Qt 内置的⽗类. Qt 中提供的很多类都是直接或者间接继承⾃ QObject.

这⼀点的设定和 Java 是⾮常相似的

2.1 connect

(1)功能

connect函数是Qt框架中实现信号槽机制的核心函数,用于在对象之间建立通信连接。它是Qt最重要的特性之一,实现了对象间的松耦合通信。

(2)函数原型

复制代码
connect (const QObject *sender, 
         const char * signal ,
         const QObject * receiver , 
         const char * method , 
         Qt::ConnectionType type = Qt::AutoConnection )

(3)函数参数

  1. sender:发送信号的对象指针
  2. signal:信号的标识(函数指针或SIGNAL宏)
  3. receiver:接收信号的对象指针
  4. slot:槽函数的标识(函数指针或SLOT宏)
  5. 连接类型(可选参数):指定连接类型,默认为AutoConnection

(4)链接类型

|------------------------------|------------------------------------------------------|
| 类型 | 描述 |
| Qt::AutoConnection | 自动选择(默认),如果同线程则用DirectConnection,否则用QueuedConnection |
| Qt::DirectConnection | 直接连接,信号发出时立即调用槽函数(同步调用) |
| Qt::QueuedConnection | 队列连接,信号发送到接收者的事件队列(异步调用) |
| Qt::BlockingQueuedConnection | 阻塞队列连接,类似QueuedConnection但发送线程会阻塞 |
| Qt::UniqueConnection | 与其他类型组合使用,确保连接是唯一的 |

(5)代码示例

复制代码
#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->move(200, 200);
    button->setText("close windows");

    // 设置槽函数
    connect(button, &QPushButton::clicked, this, &Widget::func);

}

void Widget::func()
{
    // 关闭窗口
    QWidget::close();
}

2.2 内置信号与槽函数

统⾃带的信号和槽通常是通过 "Qt 帮助⽂档" 来查询
如要查询 "按钮" 的信号,在帮助⽂档中输⼊: QPushButton

  1. ⾸先可以在 "Contents" 中寻找关键字 signals
  2. 如果没有找到, 继续去⽗类中查找. 因此我们去他的⽗类 QAbstractButton 中继续查找关键字 signals

2.3 自动生成信号与槽

Qt Creator 可以快速帮助我们⽣成信号槽相关的代码,并且除了可以通过 connect 来连接信号槽之外**,还可以通过函数名的方式自动连接**

说明:

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

1、以 " on " 开头,中间使⽤下划线连接起来;

2、" XXX " 表⽰的是对象名(控件的 objectName 属性)。

3、" SSS " 表⽰的是对应的信号。

如:" on_pushButton_clicked() " ,pushButton 代表的是对象名,clicked 是对应的信号

(1)进入UI界面

(2)在 UI 设计窗⼝中选择一个控件

(3)可视化⽣成槽函数

(4)⾃动⽣成槽函数原型框架

(5)⾃动⽣成槽函数原型框架

3 自定义信号与槽


3.1 槽函数

槽函数本质就是一个函数,在QT5以及更高的版本中,槽函数和普通成员函数之间没啥差别了

(1)自定义槽函数书写规范

早期的 Qt 版本要求槽函数必须写到 "public slots" 下,但是现在⾼级版本的 Qt 允许写到类的"public" 作⽤域中或者全局下;

复制代码
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots:
    // 槽函数
    void func();
private slots:
    void on_pushButton_clicked();
private:
    Ui::Widget *ui;
};
  • 返回值为 void,需要声明,也需要实现;
  • 可以有参数,可以发⽣重载

(2)代码示例

3.2 信号

QT中信号是一类特殊的函数,信号只需要给出函数的声明即可,这个函数的定义是在QT编译的过程中自动生成的(人为无法干预)

信号在QT中是特殊的机制,QT生成的信号函数的实现,需要配合QT框架进行很多既定的操作

  1. 信号本质就是成员函数。特殊的是该函数的定义是QT自动生成的,我们只需要写函数声明即可
  2. 信号需要定义在signals关键字中3.3 信号和槽带有参数
  3. 使用emit来自己发射信号(也可以省略不写)

(1)自定义信号函数书写规范

  1. ⾃定义信号函数必须写到 "signals" 下;
  2. 返回值为 void,只需要声明,不需要实现;
  3. 可以有参数,也可以发⽣重载;

(2)发送信号

QT内置的信号,不需要手动通过代码来进行触发,用户在进行GUI操作时就会自动触发相应的信号(发射信号的代码已经内置在QT框架中了)

使⽤ "emit" 关键字发送信号

"emit" 是⼀个空的宏。"emit" 其实是可选的,没有什么含义,只是为了提醒开发⼈员

(3)代码示例

3.3 信号和槽带有参数

Qt 的信号和槽也⽀持带有参数, 同时也可以⽀持重载.

要求:

  1. 信号函数的参数列表要和对应连接的槽函数参数列表的类型一致
  2. **参数列表的数量不要求一致,**但是信号函数列表的数量要求大于等于槽函数的参数列表的数量

此时信号触发, 调⽤到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中,通过这样的机制, 就可以让信号给槽传递数据了

(1)参数列表一致

(2)参数列表不一致

4 信号与槽的连接方式


4.1 一对一

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

4.3 多对一

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

4.3 多对一

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

5 解除连接关系


5.1 disconnect

(1)功能

disconnect 函数是Qt信号槽机制中用于断开连接的重要函数,与connect函数相对应。正确使用disconnect 可以避免信号槽的意外触发和内存泄漏。

(2)函数原型

复制代码
bool QObject::disconnect(
    const QObject *sender,        // 发送者对象指针
    const char *signal,          // 信号标识
    const QObject *receiver,     // 接收者对象指针
    const char *method           // 槽函数标识
);

(3)函数参数

|----------|----------------------------|
| 参数 | 说明 |
| sender | 发送信号的对象指针,nullptr表示匹配任何发送者 |
| signal | 信号标识,nullptr表示匹配任何信号 |
| receiver | 接收槽的对象指针,nullptr表示匹配任何接收者 |
| method | 槽函数标识,nullptr表示匹配任何槽 |

(4)代码示例

复制代码
// 先建立连接
connect(button, &QPushButton::clicked, this, &MyClass::onButtonClicked);
// 需要时断开连接
disconnect(button, &QPushButton::clicked, this, &MyClass::onButtonClicked);

// 断开button作为发送者的所有连接
button->disconnect();
// 断开this作为接收者的所有连接
this->disconnect();

// 断开所有连接到button的clicked信号的连接
disconnect(button, &QPushButton::clicked, nullptr, nullptr);

6 Lambda表达式


如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过 Lambda表达式来达到这个⽬的。

Lambda表达式 是 C++11 增加的特性。C++11 中的 Lambda表达式 ⽤于定义并创建匿名的函对象,以简化编程⼯作

7 信号与槽的优缺点


(1)优点: 松散耦合

信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了⾃⼰,Qt的信号槽机制保证了信号与槽函数的调⽤。⽀持信号槽机制的类或者⽗类必须继承于 QObject类。

(2)缺点: 效率较低

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

相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00613 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术13 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript