Qt 信号和槽学习

2023-11-02

使用一个按钮按下时,我们可能想要窗口的 close()函数被调用。这个操作可以通过设置回调函数实现。但回调函数不够直观,而且容易出现参数类型错误等问题。Qt中使用的代替方案是信号和槽机制。

信号和槽

当特定的事件出现时,一个信号被发出。槽函数作为信号的响应被调用。Qt的控件包含许多预定义的信号和槽函数。

信号槽机制是类型安全的:信号和槽函数的签名必须是匹配的。实际上,槽函数的参数可以比信号少,槽函数会忽略多出来的参数。发出信号的类不知道也不关心哪些槽函数会收到信号。信号槽机制保证信号发出来时,连接到该信号的槽函数会在正确的时间被调用。信号和槽可以带有任意数量和任意类型的参数。

所有继承自QObject或其子类的类都可以包含信号和槽。当对象的(可能被其他对象感兴趣的)状态改变时,信号可以被对象发出。

槽可以来接受信号,但同时也是普通的成员函数。正如信号不知道会被哪些槽函数接受一样,槽函数也不知道有有哪些信号连接到这个槽。

信号也可以连接到另一个信号,当前者发出后,后者会立即发出。

信号

信号实际上是一个公共访问的函数,可以在任何地方发出,但建议只从定义这个信号的类或其子类中发出。

当信号发出时,连接到信号的槽函数通常会立即被调用,就像普通函数调用一样。emit声明之后的代码会在所有的槽函数都返回之后继续执行。不同的情况是使用队列连接(queued connection)的信号槽,这种情况下,emit声明之后的代码会继续执行,而槽函数则会在稍后执行。

多个槽函数连接到同一个信号时,调用顺序为他们连接到这个信号的顺序。

信号由元对象系统自动生成,禁止在.cpp文件中实现,且返回值必须是void

经验告诉我们:信号和槽在不使用特殊类型时有更好的可复用性。即使用基本数据类型更好。

槽是可以被正常调用的C++函数,唯一的特殊功能是可以被信号连接。当直接调用槽函数时,遵循正常的C++规则。但通过信号槽的连接,槽函数可以被任意对象调用,无视槽的访问等级。也就是说来自无关的类发出的信号也可以导致被声明为私有的(private)槽被调用。

槽可以被声明为virtual的,这在实践中被发现很有用。

与回调函数相比,信号槽由于提高了灵活性而略慢,尽管在实际应用程序中的差异微不足道。通常,发射一个连接到槽函数的信号比直接调用接受者的非虚函数要慢10倍。因为需要定位连接的对象,检查接收者是否已经被删除,处理参数等。10倍听起来有点多,但这比任何newdelete操作要少得多。

带默认参数的信号和槽

信号和槽可以包含参数,参数可以有默认值。如QObject::destroyed

void destroyed(QObject* = nullptr);

当QObject对象被delete时,这个对象发出QObject::destroyed()信号。我们希望在对这个对象有引用的地方捕捉这个信号,然后清理对它的引用。适当的槽函数签名为:

void objectDestroyed(QObject* obj = nullptr);

我们使用QObject::connect()连接信号和槽。多种方法可以连接信号和槽。

第一种是使用函数指针:

connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);

使用函数指针的好处是,允许编辑器检查信号和槽的签名是否兼容;在需要的时候,参数可以被编译器隐式地转换。

也可以连接信号到lambda:

connect(sender, &QObject::destroyed, this, [=](){ this->m_objects.remove(sender); });

上面两个例子都提供this作为调用connect的上下文。上下文对象提供在哪个线程执行接收者代码的信息。即接收者的代码在上下文线程中执行。

当发送者或接收者被销毁时,lambda也被断开连接。使用者需要保证在lambda函数体内使用的对象在信号触发时仍然是存活的。

第二种是使用SIGNALSLOT宏定义。

如果参数具有默认值,则传给 SIGNAL 宏的签名的参数不能比 SLOT 的少。

正确:

connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

错误:

// 编译可以通过,但运行时错误
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

总结

  • 信号和槽通过 QObject::connect() 函数连接。
  • 信号和槽相互都不关心对方。
  • 槽触发的顺序为连接到信号的顺序。
  • 信号可以连接到信号。
  • 信号和槽可以带参数,且信号的参数不能比槽的参数少。
  • 槽函数是普通的 c++ 函数,除了承担接受信号的功能外与普通函数一样。
  • 槽函数可以是 lambda。
  • 信号槽机制比普通的函数调用慢。
  • 槽函数的执行线程在接收者所在线程。

参考:
Signals & Slots

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt 信号和槽学习 的相关文章

  • 如何在Qt3D中优化点云渲染

    我正在尝试使用 Qt3D 显示大型点云 20M pts 我第一次发现这个图书馆https github com MASKOR Qt3DPointcloudRenderer https github com MASKOR Qt3DPointc
  • C++ QT libXL 错误:“启动期间程序退出,代码为 0xc0000135”

    我正在尝试编写一个使用 libXL 的 QT 应用程序 但是当我尝试编译时 我收到一个弹出框 显示 During Startup program exited with code 0xc0000135 我已经准确地找出了哪一行导致了问题 它
  • MSVC C4100:“应用程序”:未引用的形式参数警告

    使用 MSVC 编译时 以下代码会生成 C4100 警告 这怎么可能 显然引用了 应用程序 class ApplicationInfo public QObject Q OBJECT public static void initializ
  • 在 QtCreator 中调试时如何查看 qDebug 消息

    我正在从 Eclipse CDT 带有 Qt 集成插件 过渡到 QtCreator 2 0 但仍有一件事困扰着我 QtCreator 当我在 QtCreator 中调试时 我在Application output tab直到我停止正在调试的
  • 如何使用bind将成员函数作为函数指针传递?

    我试图将成员函数作为函数指针传递 这样我就不需要依赖单例或全局函数来处理 Qt 5 中的 Qt 消息 据我所知 我的 std function 是正确的类型 它具有正确的签名 并且绑定应该允许我插入隐式this指针 本质上是将成员函数传递为
  • MapItemView 在 dataChanged 信号后不会更新

    我正在使用 QMLMapItemView使用 C 的组件QAbstractListModel基于模型 这MapItemView当模型重置时 或者每当添加新项目或删除现有项目时 工作正常 但是 那MapItemView不反映对已添加项目的更改
  • 在 QML 中控制纹理 3D 对象的不透明度

    我对 QML 中的 Qt 3D 有点陌生 我正在尝试控制 Qt 3D 的不透明度textured3D 对象 我正在使用简单qml3d https github com tripolskypetr simpleqml3d测试项目来做到这一点
  • 如何从键盘为 QTableWidget 创建信号?

    我有一张桌子 可以通过左 右 上 下按钮在里面移动 现在 当我停留在某个单元格并按空格键时 我需要创建一个信号 该信号还应该带来该单元格的坐标 我尝试使用 QTableWidget 的标准信号 但它不起作用 我该如何解决这个问题 创建一个单
  • 我如何告诉 QTableWidget 结束编辑单元格?

    我正在显示一个弹出菜单来选择 QTableWidget 中的某些值 最下面的项目是 修改列表 条目 当我选择它时 应自动出现一个新窗口 并且 QComboBox 应消失 并且单元格返回到 Qt DisplayRole 状态 现在 Qt 拥有
  • Qt - 意外的 GDB 退出

    我正在尝试开发一个应用程序 该应用程序创建图像并使用双线性插值填充颜色像素 然后显示它 到目前为止我的代码如下 include
  • 如何阻止 Qt Creator 将可执行文件放置在“调试”子目录中?

    我正在 Qt Creator 中构建一个项目 虽然我不关心中间 obj 文件去哪里 但重要的是最终的可执行文件应放入 并运行 许多依赖项 DLL 等所在的特定目录中 被发现 因此 在 Qt Creator 中 我选择 Shadow Buil
  • QListWidget 拖放项目从 Symbian 列表中消失

    我在实现带有可通过拖放重新排序的自定义项的 QListWidget 时遇到问题 问题是当我在某个项目上快速双击 非常短的拖放 时 该项目有时会从 QListWidget 中消失 这是我的小部件的构造函数 ListPopisiDragDrop
  • 通过CMake实现Qt项目

    我正在尝试通过 Cmake 构建并运行非常简单且基本的 Qt 示例 删除 pro 文件 以下是Qt项目的代码 自动生成的Qt项目的目录结构为 Cmake my project name headers mainwindow h source
  • Qt 5.5 QOpenGLWidget 链接错误未链接任何 openGL 调用

    我尝试使用 Qt 5 5 1 构建一个简单的 OpenGL 应用程序 一切都很好 直到我尝试使用 glClearColor 等 openGL 本机函数调用 该小部件实际上编译并产生黑屏 但在我尝试使用任何 openGL 本机函数后 它甚至不
  • 加载 QPixmap 数据的更好方法

    更好的方法来做到这一点 没有QImage QImage image width height QImage Format RGB888 memcpy image bits m frameRGB gt data 0 height width
  • 在 Qt 5 中嵌入 Python

    我想将 Python 解释器嵌入到 Qt 5 应用程序中 我在 Qt 5 中有一个工作应用程序 但是当我把 include
  • 获取 QPushButton 在 2D 数组 QPushButton 上的索引

    我有一个二维数组QPushButton 当用户单击按钮时如何获取按钮的索引 例如当用户单击按钮时a 2 3 它会显示 2 3 该示例如下所示 Qt 4 5 使用对象名称 您可以为按钮指定唯一的对象名称 理想情况下 名称应该是有效的 C 标识
  • 如何从浮点数组创建新的 QImage

    我有一个代表图像的浮点数数组 列在前 我想在 QGraphicsSecene 上将图像显示为 QPixmap 为了做到这一点 我尝试使用 QImage 构造函数 QImage const uchar data int width int h
  • 我应该使用 QCoreApplication::processEvents() 还是 QApplication::processEvents()?

    我有一个从两者调用的方法QThreads和主线程 这个方法有时可能需要很长时间才能在循环中进行计算 所以我把QCoreApplication processEvents 这可以防止 GUI 冻结 在某个时刻我已经改变了QCoreApplic
  • PyQt - 如何从给定的小部件获取顶级父级?

    给定的小部件如何访问它最旧的父级 即顶级小部件 我需要 showMinimized it 现在我正在使用 self parent parent parent showMinimized 但这似乎不是最好的方法 如果它移动了 我需要手动更改父

随机推荐

  • 滚动页面到指定位置动画展示-Vue自定义命令-IntersectionObserver-animate.css

    最近在做公司官网 web H5 页面滚动显示出来给个小动画 之前了解的浏览器标准解决方案 不向下兼容 是 IntersectionObserver 是一个全局的侦听器 但是每个页面去做一个实例去侦听当前对象也觉得太冗余了吧 并且在vue里面
  • 逻辑分析仪的使用

    目录 逻辑分析仪与示波器的区别 逻辑分析仪 DSView 软件安装与简介 波形采集 波形分析 分析I2S协议 逻辑分析仪与示波器的区别 参考 https www bilibili com video BV1mz4y127jn spm id
  • 详解环境变量

    目录 前言 一 什么是环境变量 二 查看环境变量的方法 三 查看环境变量的内容 四 普通变量VS环境变量 五 导出环境变量 六 常见的环境变量 七 set命令 查看普通变量或环境变量 八 C C 语言中main函数中的参数 1 main函数
  • C#操作Excel总结

    0 导入命名空间 1 2 3 4 using Microsoft Office Core using Microsoft Office Interop Excel
  • 1-8、Lua编译-运行-错误信息

    1 8 Lua编译 运行 错误信息 文章目录 1 8 Lua编译 运行 错误信息 1 require函数 2 C Packages 3 错误 4 异常和错误处理 5 错误信息和回跟踪 Tracebacks 虽然我们把Lua当作解释型语言 但
  • JNDI 和 JDBC 的区别-个人理解

    公众号 BiggerBoy 分享了更多知识干货 欢迎关注 多多支持 网上关于 JNDI 和 JDBC 的定义有很多 但是都很官方不容易理解 下面是我最近查阅资料得出的心得体会 希望对你在理解上有一点点的帮助 说的不对的请指正哦 JDBC 看
  • Sharding-jdbc踩坑记录(一)

    sharding jdbc学习链接 sharding jdbc版本 2 0 3 springboot版本 2 1 5 连接池 druid 1 1 14
  • 解决Bug[Vue warn]Error in mounted hook: “Error: please transfer a valid prop path to form item“

    本文主要讲解el form里嵌套el table的报错和解决 报错 Vue warn Error in mounted hook Error please transfer a valid prop path to form item 报错
  • PyTorch中通过torch.save保存模型和torch.load加载模型介绍

    PyTorch中一般约定是使用 pt或 pth文件扩展名保存模型 通过torch save保存模型 通过torch load加载模型 torch save和torch load函数的实现在torch serialization py文件中
  • Java根据枚举名使用反射获取枚举值

    由于前端需要根据枚举名获取实时获取枚举值 所以通过反射去得到枚举数据 一 首先我们新建一个枚举类接口 用于之后反射使用 package com littlematch enums biz 枚举值接口定义类 public interface
  • Eclipse导入工程文件后出现红叉解决方案:

    Step1 右击工程文件名 然后点击buildPath step2 点击Library 再点击JRE System Librarystep3 双击JRE System Library 选最后一个 Workspace default JRE
  • C++ 多线程:原子操作atomic

    原子操作atomic C 多线程 原子类型 有两个线程 一个要写数据 一个读数据 如果不加锁 可能会造成读写值混乱 使用std mutex程序执行不会导致混乱 但是每一次循环都要加锁解锁是的程序开销很大 为了提高性能 C 11提供了原子类型
  • 四二拍用音符怎么表示_钢琴教学:学会这3个音符!立马解决你节奏的致命问题!...

    在学习节奏之前 我们先来了解节奏是什么 以及节奏的重要性 一切协调 平衡 有次序的进行都可以称为节奏 节奏可以独立存在 而在音乐中具体表现为 用强弱相互交替 将音的长短关系组织起来 称为节奏 许多节奏的组合在音乐进行中已经形成固定的模式 而
  • 1.3编程基础之算术表达式与顺序执行 06:甲流疫情死亡率

    1 3编程基础之算术表达式与顺序执行 06 甲流疫情死亡率 总时间限制 1000ms 内存限制 65536kB 描述 甲流并不可怕 在中国 它的死亡率并不是很高 请根据截止2009年12月22日各省报告的甲流确诊数和死亡数 计算甲流在各省的
  • java web开发一个帐号同一时间只能一个人登录

    一个帐号同一时间只能一个人登录 对于一个帐号在同一时间只能一个人登录 可以通过下面的方法实现 1 在用户登录时 把用户添加到一个ArrayList中 2 再次登录时查看ArrayList中有没有该用户 如果ArrayList中已经存在该用户
  • springboot实现各种参数校验

    springboot实现各种参数校验 简单使用 Java API规范 JSR303 定义了Bean校验的标准validation api 但没有提供实现 hibernate validation是对这个规范的实现 并增加了校验注解如 Ema
  • 【JavaWeb】JSP使用Session、Cookie实现购物车

    购物界面shop jsp 初始页面 添加商品后 在session中设置属性 重定向回到shop jsp 然后根据session的内容显示结果 Cookie设置setMaxAge可以延长session的寿命 清空购物车就是清除session
  • 基于以太坊的USDT(基于ERC-20协议发行)

    这种USDT存储在以太坊地址上 相对应的 每次转账 链上转账 时 需要消耗Gas 也就是ETH 目前 市场上的USDT绝大部分是基于比特币的USDT 基于以太坊的USDT份额很低 约3 基于TRON网络TRC20协议的USDT 存储在TRO
  • 当心互联网抢了你的饭碗

    两年前 供职于帕洛阿尔托研究中心 Palo Alto Research Center 的学者布莱恩 亚瑟 Brian Arthur 做出了一项惊人预测 未来二三十年 西方数字网络履行的功能最终将相当于美国 实体 经济的规模 亚瑟写道 或者
  • Qt 信号和槽学习

    使用一个按钮按下时 我们可能想要窗口的 close 函数被调用 这个操作可以通过设置回调函数实现 但回调函数不够直观 而且容易出现参数类型错误等问题 Qt中使用的代替方案是信号和槽机制 信号和槽 当特定的事件出现时 一个信号被发出 槽函数作