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

【QT 一 | 信号和槽】

Qt5基本模块

在这里插入图片描述

Qt Creator 中的快捷键

• 注释:ctrl + /
• 运⾏:ctrl + R
• 编译:ctrl + B
• 字体缩放:ctrl + 鼠标滑轮
• 查找:ctrl + F
• 整行移动:ctrl + shift + ⬆/⬇
• 帮助⽂档:F1
• 自动对齐:ctrl + i;
• 同名之间的 .h 和 .cpp 的切换:F4
• 生成函数声明的对应定义: alt + enter

认识对象模型(对象树)

在 Qt 中,对象树是一种非常重要的概念,用于管理和组织对象之间的关系。以下是对 Qt 对象树的详细理解介绍:

1. 对象树的基本概念

  • 定义:Qt 的对象树是一种层次化的对象管理机制,基于 QObject 类实现。每个 QObject 对象可以有一个父对象(parent),并且可以拥有多个子对象(children)。
  • 父子关系:当创建一个 QObject 对象时,可以通过构造函数指定一个父对象。如果指定了父对象,那么这个新创建的对象会自动成为父对象的子对象,并被添加到父对象的 children() 列表中。

2. 对象树的作用

  • 生命周期管理:父对象负责管理其子对象的生命周期。当父对象被销毁时,其所有子对象也会被自动销毁。这种机制避免了内存泄漏,同时也简化了对象的管理。

  • 事件传播:在 GUI 程序中,事件(如鼠标点击、键盘输入等)会从父对象向下传播到子对象。这种机制使得事件处理更加高效和灵活。

  • 组件化管理:对象树使得 GUI 组件的组织更加清晰。例如,一个窗口(QWidget)可以包含多个按钮、文本框等子组件。当窗口被销毁时,所有子组件也会被自动销毁。

3. 对象树的实现机制

  • 构造函数中的父对象参数QObject 的构造函数接受一个 QObject* 类型的参数,表示父对象。例如:
    QObject* parent = new QObject();
    QObject* child = new QObject(parent);
    
    在这个例子中,child 的父对象是 parentchild 会被自动添加到 parentchildren() 列表中。
  • children() 方法:每个 QObject 对象都有一个 children() 方法,返回一个包含所有子对象的列表。
  • 自动销毁机制:当父对象被销毁时,Qt 会自动调用子对象的析构函数,销毁所有子对象。

4. 对象树的使用场景

  • GUI 组件管理:在 Qt 的 GUI 程序中,QWidget 是所有可视组件的基类,它继承自 QObject。例如:
    QWidget* window = new QWidget();
    QPushButton* button = new QPushButton(window);
    
    在这个例子中,buttonwindow 的子组件。当 window 被销毁时,button 也会被自动销毁。
  • 资源管理:对象树机制不仅适用于 GUI 组件,还可以用于管理其他资源,如文件句柄、网络连接等。

5. 注意事项

  • 避免循环引用:在使用对象树时,要避免创建循环引用(即对象 A 是对象 B 的父对象,同时对象 B 也是对象 A 的父对象)。这会导致对象无法正确销毁,从而引发内存泄漏。
  • 手动管理子对象:虽然对象树会自动管理子对象的生命周期,但也可以手动删除子对象。例如:
    QObject* child = new QObject(parent);
    delete child;  // 手动删除子对象
    
    在这种情况下,子对象会从父对象的 children() 列表中自动移除。

Qt 的对象树是一种强大的机制,用于管理和组织对象之间的关系。它不仅简化了内存管理,还使得 GUI 组件的组织更加清晰。通过合理使用对象树,可以提高代码的可维护性和可扩展性。
在 Qt 中,尽量在构造的时候就指定parent对象,并且⼤胆在堆上创建。
在这里插入图片描述## 信号与槽
如果要使用信号与槽(signal 和 slot)的机制就必须加入Q_OBJECT宏;这个宏不仅用于支持信号与槽机制,还允许 Qt 的元对象系统(Meta-Object System)自动生成一些辅助代码。

信号的本质就是事件。

  • 如:按钮单击、双击 ,窗⼝刷新等。
  • 信号的呈现形式就是函数
  • 信号函数只需要声明,不需要定义(实现)。
  • 信号函数声明用 signals 关键字修饰

槽(Slot)就是对信号响应的函数。

  • 槽是普通的成员函数,用于处理信号。槽函数可以手动实现,也可以通过 Qt 的机制自动生成。
  • 可以定义在类的任何位置( public、protected 或 private)。
  • 可以具有任何参数,可以被重载,也可以被直接调
    用(但是不能有默认参数
  • 槽函数需要定义(实现)。
  • 槽函数可以与⼀个信号关联,当信号被发射时,关联的槽函数被自动执行。
  • 槽函数用 public slots、protected lots 或者 private slots 修饰。

signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字

connect函数

在 Qt 中,QObject 类提供了⼀个静态成员函数connect(),该函数专门来关联指定的信号函数和槽函数。
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,通常不需要手动设定。

自动生成槽函数的机制

  • 步骤
    1. 在 Qt Creator 中,添加一个信号( mySignal(int value)
    2. 右键点击信号或信号声明。
    3. 选择 “转到槽”(Go to Slot)或 “转到信号”(Go to Signal)。
    4. Qt Creator 会自动生成一个槽函数的声明和定义,并将其添加到类中。

例如,对于信号 mySignal(int value),Qt Creator 会生成如下代码:

// 在头文件中自动生成槽函数声明
public slots:
    void on_mySignal(int value);

// 在实现文件中自动生成槽函数定义
void MyObject::on_mySignal(int value)
{
    // 在这里实现槽函数的逻辑
}
  • 自动生成的槽函数
    • 当你在类中声明信号时,Qt 的元对象系统会自动为这些信号生成默认的槽函数。这些槽函数通常以 on_<SignalName> 的形式命名。
    • 按照这种命名风格格定义的槽函数,会被 Qt ⾃动的和对应的信号进行连接。
      日常写代码,最好还是不要依赖命名规则,而是显式
      使用 connect 更好。1. connect 可以更清晰直观的描述信号和槽的连接关系。2. 防止信号或者槽的名字拼写错误导致连接失效.
  • 使用方法
    • 在类的声明中,添加信号声明。
    • 在类的实现中,实现自动生成的槽函数。
    • 使用 QObject::connect() 将信号连接到自动生成的槽函数。
通过 Qt 的 Q_INVOKABLE

Q_INVOKABLE 宏可以将普通成员函数标记为可调用的槽函数。虽然这不是严格意义上的“自动生成”,但它允许开发者将任意函数作为槽函数使用。

  • 使用方法
    • 在类的声明中,使用 Q_INVOKABLE 宏标记成员函数。
    • 这些函数可以直接作为槽函数使用。

例如:

class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject(QObject* parent = nullptr);

    Q_INVOKABLE void mySlotFunction(int value);  // 使用 Q_INVOKABLE 标记

signals:
    void mySignal(int value);
};

void MyObject::mySlotFunction(int value)
{
    qDebug() << "Slot function called with value:" << value;
}

// 连接信号和槽
connect(this, &MyObject::mySignal, this, &MyObject::mySlotFunction);

自定义信号函数和槽函数

  1. ⾃定义信号函数书写规范
    (1)⾃定义信号函数必须写到 “signals” 下;
    (2)返回值为 void,只需要声明,不需要实现;
    (3)可以有参数,也可以发生重载
  2. ⾃定义槽函数书写规范
    (1)早期的 Qt 版本要求槽函数必须写到 “public slots” 下,但是现在⾼级版本的 Qt 允许写到类的 “public” 作用域中或者全局下;
    (2)返回值为 void,需要声明,也需要实现;
    (3)可以有参数,可以发生重载;
    3、发送信号
    使用 “emit” 关键字发送信号。“emit” 是⼀个空的宏。"emit"其实是可选的,没有什么含义,只
    是为了提醒开发⼈员。

关联函数一定要在发射信号之前
原因是,⾸先关联信号和槽,⼀旦检测到信号发射之后就会立即执行关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应。

信号与槽的断开

在这里插入图片描述
当"connect"函数第三个参数为"this" 时,第四个参数使⽤ Lambda表达式时,可以省略掉 “this”


http://www.kler.cn/a/563812.html

相关文章:

  • 技术分享:MyBatis 动态 SQL 的应用 <choose>, <when>, <otherwise>
  • 如何用python将pdf转为text并提取其中的图片
  • 细说STM32F407单片机RS485收发通信实例及调试方法
  • pycharm远程连接服务器运行pytorch
  • <02.26>Leetcode
  • 航旅纵横测试开发一面面经
  • PyTorch下三角矩阵生成函数torch.tril的深度解析
  • Python 高级特性-迭代器
  • 机器学习01
  • servlet相关
  • 【漫画机器学习系列】102.带泄露线性整流函数(Leaky ReLU)
  • playwright GitHub Actions运行测试
  • Fetch 是用于发起HTTP请求的API body 部分
  • 服务器主板可以单独升级吗?有什么影响?
  • 超过DeepSeek、o3,Claude发布全球首个混合推理模型,并将完成新一轮35亿美元融资...
  • 上海商米科技通信工程师后端开发岗内推
  • 从 0 到 1:使用 Docker 部署个人博客系统
  • 【Python爬虫(88)】当Python爬虫邂逅智能硬件:解锁数据新玩法
  • git设置本地代理
  • IO 和NIO有什么区别?