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

Qt6入门教程 8:信号和槽机制(连接方式)

目录

一.一个信号与槽连接的例子

二.第五个参数

1.Qt::AutoConnection

2.Qt::DirectConnection

3.Qt::QueuedConnection

4.Qt::BlockingQueuedConnection

5.Qt::UniqueConnection

三.信号

四.connect函数原型

五.信号与槽的多种用法

六.槽的属性


一.一个信号与槽连接的例子

#include <QObject>
#include <QDebug>class Counter : public QObject
{Q_OBJECTpublic:Counter() { m_value = 0; }int value() const{return m_value;}public slots:void setValue(int value){if (value != m_value){m_value = value;emit valueChanged(value);}}signals:void valueChanged(int newValue);private:int m_value;
};int main(int argc, char *argv[])
{Counter a, b;QObject::connect(&a, &Counter::valueChanged,&b, &Counter::setValue);a.setValue(12); // a.value() == 12, b.value() == 12qDebug() << "a: " << a.value() << " b: " << b.value();b.setValue(48); // a.value() == 12, b.value() == 48qDebug() << "a: " << a.value() << " b: " << b.value();return 0;
}#include "main.moc"

在调用a.setValue(12)时会发送valueChanged(12)信号,此时槽函数b.setValue(12)会被调用。然后b也会发送valueChanged(12)信号,但是由于没有槽连接到这个信号,所以这个信号被忽略了,不做处理。
需要注意的是,在setValue()函数中在赋值和发送信号之前做了 value != m_value的判断。这样做是为了防止特定情况下触发的无限循环调用,比如此时b.valueChanged()连接到了a.setValue()。

二.第五个参数

在上面的例子中,调用connect()函数时并没有指定第五个参数,因第五个参数一般不填,为默认值。

1.Qt::AutoConnection

默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

2.Qt::DirectConnection

槽函数会在信号发送的时候直接被调用,槽函数和信号发送者在同一线程。效果看上去就像是直接在信号发送位置调用了槽函数,同步执行。
emit语句后面的代码将在与信号关联的所有槽函数执行完毕后才被执行。
无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行。但需要注意的是,当信号和槽在不同的线程时,Qt::DirectConnection连接方式是不安全的,就像不能直接调用不同线程中的函数一样。但QObject::connect() 方法本身是线程安全的。

3.Qt::QueuedConnection

信号发出后,信号会暂时被放到一个消息队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作。
emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。
槽函数在接收者所依附线程执行。

4.Qt::BlockingQueuedConnection

槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。而且接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

// Qt部分源码如下
.....//其他代码
else if(type == Qt::BlockingQueuedConnection)
{if(currentThread == objectThread) // 如果是同一条线程,就死锁了qWarning("QMetaObject::invoke: Dead lock detected");QSemaphore semaphore; // 信号量QCoreApplication::postEvent(Object, new QMetaCallEvent(slot, 0, -1, 0, 0, qrgv, &semaphore));  // 将函数指针、函数参数、信号量的指针发送到事件队列semaphore.acquire(); // 默认形参为1,;获取1个数据,如果没有准备1个好数据,则阻塞
}
else
{
.... //其他代码
}

5.Qt::UniqueConnection

这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是为了避免重复连接。

三.信号

声明信号使用signals关键字,发送信号使用emit关键字。
注意点:
1.所有的信号声明都是公有的,所以Qt规定不能在signals前面加public、private、protected。
2.所有的信号都没有返回值,所以返回值都用void。
3.所有的信号都不需要定义。
4.必须直接或间接继承自QOBject类,并且开头私有声明包含Q_OBJECT。
5.在同一个线程中,当一个信号被emit发出时,会立即执行其槽函数,等槽函数执行完毕后,才会执行emit后面的代码,如果一个信号链接了多个槽,那么会等所有的槽函数执行完毕后才执行后面的代码,槽函数的执行顺序是按照它们链接时的顺序执行的。不同线程中(即跨线程时),槽函数的执行顺序是随机的。
6.在链接信号和槽时,可以设置链接方式为:在发出信号后,不需要等待槽函数执行完,而是直接执行后面的代码,是通过connect的第5个参数。
7.信号与槽机制要求信号和槽的参数一致,所谓一致,是参数类型一致。如果不一致,允许的情况是,信号的参数可以比槽函数的参数多,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少),但是不能说信号根本没有这个数据,你就要在槽函数中使用(就是槽函数的参数比信号的多,这是不允许的)。

四.connect函数原型

1.如:connect(pushButton, SIGNAL(clicked()), dialog, SLOT(close()));Qt4和Qt5都可以使用这种连接方式。

static QMetaObject::Connection connect(const QObject *sender,    //信号发送对象指针const char *signal,       //信号函数字符串,使用SIGNAL()const QObject *receiver,  //槽函数对象指针const char *member,       //槽函数字符串,使用SLOT()Qt::ConnectionType = Qt::AutoConnection);

2.如:connect(pushButton, &QPushButton::clicked, dialog, &QDialog::close);这是Qt5新增的连接方式,在编译期间就可以进行类型检查,推荐使用这种连接方式。

static QMetaObject::Connection connect(const QObject *sender,      //信号发送对象指针const QMetaMethod &signal,  //信号函数地址const QObject *receiver,    //槽函数对象指针const QMetaMethod &method,  //槽函数地址Qt::ConnectionType type = Qt::AutoConnection);

3.两者的对比

概述基于字符串的语法基于函子的语法
做类型检查的阶段运行时编译时
是支持行类型的隐式转换
是否支持信号连接到lambda表达式
是否支持槽的参数比信号的参数多(此时槽使用默认参数)
是否支持连接C++函数到QML函数

注:qt5之后,这种新型的写法,支持所有的函数类型,无需定义slots关键字也可以。

如何选择重载的信号和槽呢?例如,QLCDNumber有三个版本的display()槽:
●QLCDNumber::display(int)
●QLCDNumber::display(double)
●QLCDNumber::display(QString)
将槽连接到int版本的QSlider::valueChanged()信号, 两种语法的写法如下:

auto slider = new QSlider(this);
auto lcd = new QLCDNumber(this);// 基于字符串的语法
connect(slider, SIGNAL(valueChanged(int)),lcd, SLOT(display(int)));// 基于函子的语法,第一种方式(推荐)
connect(slider, &QSlider::valueChanged,lcd, static_cast<void (QLCDNumber::*)(int)>(&QLCDNumber::display));// 基于函子的语法,第二种方式
void (QLCDNumber::*mySlot)(int) = &QLCDNumber::display;
connect(slider, &QSlider::valueChanged,lcd, mySlot);// 基于函子的语法,第三种方式
connect(slider, &QSlider::valueChanged,lcd, QOverload<int>::of(&QLCDNumber::display));// 基于函子的语法,第四种方式(C++14)
connect(slider, &QSlider::valueChanged,lcd, qOverload<int>(&QLCDNumber::display));

在需要信号发送方信息的情况下,Qt提供了QObject::sender()函数,它返回一个指向发送信号的对象的指针。如下所示:

void MyWidget::on_pushButton_clicked()
{QPushButton *button = static_cast<QPushButton*>(QObject::sender());qDebug() << button->text(); 
}

五.信号与槽的多种用法

1.一个信号可以和多个槽相连
2.多个信号可以连接到一个槽
3.一个信号可以连接到另外的一个信号
4.槽可以被取消链接.
其写法和connect一样,只需要将connect换成disconnect即可。
disconnect() 通常以三种方式使用,如下面的示例所示:
1.断开myObject对象的信号与其他对象间的连接,使用后myObject发出的信号没有对应的槽函数进行响应

disconnect(myObject, nullptr, nullptr, nullptr);
//or
myObject->disconnect();

2.断开myObject对象的mySignal()信号与其他对象间的连接,使用后myObject发出的mySignal()信号没有对应的槽函数进行响应

disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr);
//or
myObject->disconnect(SIGNAL(mySignal()));

3.断开myObject对象的与myReceiver对象间的连接,使用后myObject发出mySignal()信号myReceiver没有对应的槽函数进行响应

disconnect(myObject, nullptr, myReceiver, nullptr);
//or
myObject->disconnect(myReceiver);

六.槽的属性

public slots:在这个区内声明的槽意味着所有对象都可将信号和之相连接。这对于组件编程非常有用,你能创建彼此互不了解的对象,将他们的信号和槽进行连接以便信息能够正确的传递。 
protected slots:在这个区内声明的槽意味着当前类及其子类能将信号和之相连接。
private slots:在这个区内声明的槽意味着只有类自己能将信号和之相连接。
注:信号和槽不能携带模板类参数

原文链接:https://blog.csdn.net/caoshangpa/article/details/135639126

相关文章:

Qt6入门教程 8:信号和槽机制(连接方式)

目录 一.一个信号与槽连接的例子 二.第五个参数 1.Qt::AutoConnection 2.Qt::DirectConnection 3.Qt::QueuedConnection 4.Qt::BlockingQueuedConnection 5.Qt::UniqueConnection 三.信号 四.connect函数原型 五.信号与槽的多种用法 六.槽的属性 一.一个信号与槽连接…...

Python如何操作RabbitMQ实现fanout发布订阅模式?有录播直播私教课视频教程

fanout发布订阅模式 基本用法 生产者 import json import rabbitmq# 建立连接 credentials rabbitmq.PlainCredentials(zhangdapeng,zhangdapeng520, ) # mq用户名和密码 connection_target rabbitmq.ConnectionParameters(host127.0.0.1,port5672,virtual_host/,credent…...

QT 原生布局和QML的区别

一、QML 与 Qt Quick的区别 1.1 从概念上区分 为了更精确地对两者进行说明&#xff0c;先看助手对 QML 的描述&#xff1a; QML is a user interface specification and programming language. QML 是一种用户界面规范和标记语言&#xff0c;允许开发人员和设计师创建高性能、流…...

视频转码实例:把MP4转为MKV视频,一键批量转换的操作方法

在数字媒体时代&#xff0c;视频格式的多样性是不可避免的。经常把MP4格式的视频转换为MKV格式。MKV格式有较高的音频和视频质量&#xff0c;能在其他设备或软件上播放视频。以下是云炫AI智剪如何把MP4视频转为MKV格式的一键批量转换操作方法。 已转码的mkv视频效果缩略图展示…...

异步Merkle Tree

1. 引言 前序博客&#xff1a; 利用多核的Rust快速Merkle tree Anoushk Kharangate 2023年论文《Asynchronous Merkle Trees》&#xff0c;其对Merkle tree数据结构进行修改&#xff0c;使得可跨多线程异步计算。 开源代码实现见&#xff1a; https://github.com/anoushk1…...

7. UE5 RPG修改GAS的Attribute的值

前面几节文章介绍了如何在角色身上添加AbilitySystemComponent和AttributeSet。并且还实现了给AttributeSet添加自定义属性。接下来&#xff0c;实现一下如何去修改角色身上的Attribute的值。 实现拾取药瓶回血功能 首先创建一个继承于Actor的c类&#xff0c;actor是可以放置到…...

Oracle/DM序列基本使用

序列(SEQUENCE)是序列号生成器&#xff0c;可以为表中的行自动生成序列号&#xff0c;产生一组等间隔的数值(类型为数字)。其主要的用途是生成表的主键值&#xff0c;可以在插入语句中引用&#xff0c;也可以通过查询检查当前值&#xff0c;或使序列增至下一个值。序列是一个计…...

校验ChatGPT 4真实性的三个经典问题:提供免费测试网站快速区分 GPT3.5 与 GPT4

现在已经有很多 ChatGPT 的套壳网站&#xff0c;以下分享验明 GPT-4 真身的三个经典问题&#xff0c;帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 大家可以在这个网站测试&#xff1a;https://ai.hxkj.vip&#xff0c;免登录可以问三条&#xff0c;登录之后无限…...

概率论与数理统计————3.随机变量及其分布

一、随机变量 设E是一个随机试验&#xff0c;S为样本空间&#xff0c;样本空间的任意样本点e可以通过特定的对应法则X&#xff0c;使得每个样本点都有与之对应的数对应&#xff0c;则称XX&#xff08;e&#xff09;为随机变量 二、分布函数 分布函数&#xff1a;设X为随机变量…...

掌握单例模式的极致挑战:能否默写饿汉式代码?

目录 1.前言 2.本质 3.代码默写 1.前言 在面试中&#xff0c;理解和掌握单例模式是非常重要的。本文旨在帮助读者深入理解饿汉式单例模式&#xff0c;并通过简洁明了的解释和示例代码&#xff0c;使读者能够轻松掌握并默写出饿汉式单例模式的代码实现。 2.本质 饿汉式单例模…...

力扣刷MySQL-第三弹(详细讲解)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;力扣刷题讲解-MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出…...

PXE和kickstart无人值守安装

PXE高效批量网络装机 引言 1.系统装机的引导方式 启动 操作 系统 1.硬盘 2.光驱&#xff08;u盘&#xff09; 3.网络启动 pxe 重装系统&#xff1f; 在已有操作系统 新到货了一台服务器&#xff0c; 装操作系统 系统镜像 u盘 光盘 pe&#xff1a; 小型的 操作系统 在操…...

rabbitmq基础教程(ui,java,springamqp)

概述&#xff1a;安装看我上篇文章Docker安装rabbitmq-CSDN博客 任务一 创建一个队列 这样创建两个队列 在amq.fanout交换机里面发送数据 模拟发送数据 发送消息&#xff0c;发现一下信息&#xff1a; 所以得出理论&#xff0c;消息发送是先到交换机&#xff0c;然后由交换机…...

无重复字符的最长子串[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个字符串s&#xff0c;请你找出其中不含有重复字符的最长子串的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc"&#xff0c;所以其长度为3。 示例 2: 输入: s &…...

考研经验总结——目录

文章目录 一、写作顺序二、个人情况说明三、读评论四、一些小牢骚五、一些注意事项&#xff08;持续更新&#xff09; 一、写作顺序 我将准备从三个阶段开始介绍吧 考研前考研中考研后&#xff08;也就是现在我的这种情况&#xff09; 考研前我会分为&#xff1a;数学、专业…...

Docker(一)简介和基本概念

一、简介 本章将带领你进入 Docker 的世界。 什么是 Docker&#xff1f; 用它会带来什么样的好处&#xff1f; 好吧&#xff0c;让我们带着问题开始这神奇之旅。 1.什么是 Docker Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目&…...

openssl3.2 - 官方demo学习 - test - certs

文章目录 openssl3.2 - 官方demo学习 - test - certs概述笔记.sh的执行语句打印的方法要修改的实际函数END openssl3.2 - 官方demo学习 - test - certs 概述 官方demos目录有证书操作的例子 已经做了笔记 openssl3.2 - 官方demo学习 - certs 但是这个demos/certs目录的脚本,…...

Spring MVC学习之——异常处理器

异常处理器 如果不加以异常处理&#xff0c;错误信息肯定会抛在浏览器页面上&#xff0c;这样很不友好&#xff0c;所以必须进行异常处理。 1.异常处理思路 系统的dao、service、controller出现都通过throws Exception向上抛出&#xff0c;最后由springmvc前端控制器交由异常…...

HTTP API 认证技术详解(四):HMAC Authentication

目录 什么是 HMAC Authentication 认证 HMAC Authentication 原理 HMAC Authentication 认证的步骤 使用 Golang 实现 HMAC Authentication 认证 HMAC Authentication 认证的安全性 HMAC 认证的最佳实践 小结 HTTP API 认证技术主要用于验证客户端身份&#xff0c;并确保…...

如何绘制出图像的色素分布直方图

效果 如图&#xff0c;可以展示出我们的图像的颜色分布直方图,表明的图像的亮和暗 实现可视化色素分布直方图方法 这里我们对我们的灰色图片和彩色图片进行了直方图显示 import cv2 import matplotlib.pyplot as plt image cv2.imread("test.jpg") # 彩色图片->…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...

Xcode 16 集成 cocoapods 报错

基于 Xcode 16 新建工程项目&#xff0c;集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...

Springboot 高校报修与互助平台小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;高校报修与互助平台小程序被用户普遍使用&#xff0c;为…...

mq安装新版-3.13.7的安装

一、下载包&#xff0c;上传到服务器 https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.13.7/rabbitmq-server-generic-unix-3.13.7.tar.xz 二、 erlang直接安装 rpm -ivh erlang-26.2.4-1.el8.x86_64.rpm不需要配置环境变量&#xff0c;直接就安装了。 erl…...

Go 语言中的内置运算符

1. 算术运算符 注意&#xff1a; &#xff08;自增&#xff09;和--&#xff08;自减&#xff09;在 Go 语言中是单独的语句&#xff0c;并不是运算符。 package mainimport "fmt"func main() {fmt.Println("103", 103) // 13fmt.Println("10-3…...

Steam爬取相关游戏评测

## 因为是第一次爬取Steam。所以作为一次记录发出&#xff1b;有所错误欢迎指出。 无时间指定爬取 import requests import time import csv import osappid "553850" # 这里你也可以改成 #appid int(input()) max_reviews 10000 # 想爬多少条 # max_reviews…...

Redis 集群批量删除key报错 CROSSSLOT Keys in request don‘t hash to the same slot

Redis 集群报错 CROSSSLOT Keys in request dont hash to the same slot 的原因及解决方案 1. 错误原因 在 Redis 集群模式下&#xff0c;数据根据 哈希槽&#xff08;Slot&#xff09; 分散存储在不同的节点上&#xff08;默认 16384 个槽&#xff09;。当执行涉及多个 key …...