QT元对象系统特性详细介绍(信号槽、类型信息、动态设置属性)(注释)

目  录

一、元对象系统简介

二、信号和槽

三、类型信息

四、动态设置属性


一、元对象系统简介

QT中的元对象系统Q_OBJECT并不是C++标准代码,因此在使用时需要QT的MOC(元对象编译器)进行预处理,MOC会在编译时期读取C++代码中的特定宏(如Q_OBJECT),再由标准的C++编译器进行重新编译。

Q_OBJECT的使用:必须要在类中定义元对象系统Q_OBJECT 宏才能使用(在类定义时,如果没有指定public或者private,则默认为private(私有))。程序运行时,moc会扫描此类,并生成元对象信息,包括但不限于类名、父类、属性、信号、槽函数等;

Q_OBJECT的特性:

  • 类型信息:Qt使用元对象系统来存储关于对象的信息,如类名和父类。
  • 属性系统:支持动态的属性机制,允许在运行时查询和修改对象的属性。
  • 信号和槽的动态连接:元对象系统允许在运行时创建和解除信号与槽之间的连接。

二、信号和槽

(1)信号与槽是对象间进行通信的机制,使用QObject::connect函数连接信号和槽时,元对象系统会在运行时查找信号(signals)和槽(slots),并建立连接。使用方式如下:定义两个类,名为QtWidgetsApplication3、obj,互相通信。

QtWidgetsApplication3.h

#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication3.h"
#include <QObject> //包含头文件,以使用信号槽class QtWidgetsApplication3 : public QMainWindow
{//启用Qt的元对象系统,允许使用信号和槽等特性Q_OBJECT //默认私有
public:QtWidgetsApplication3(QWidget *parent = nullptr);~QtWidgetsApplication3();
private:Ui::QtWidgetsApplication3Class ui;
signals:    //声明信号void testsignal();
};class obj : public QObject //继承QObject使用信号槽
{//启用Qt的元对象系统,允许使用信号和槽等特性Q_OBJECT 
public: //声明构造函数,接受一个QObject指针作为父对象obj(QObject* parent = nullptr);
public slots: //声明槽void testslot();
};

QtWidgetsApplication3.cpp

#include "QtWidgetsApplication3.h"
QtWidgetsApplication3::QtWidgetsApplication3(QWidget *parent): QMainWindow(parent)
{ui.setupUi(this);obj* qobj = new obj(this);  //创建obj的实例QObject::connect(this,&QtWidgetsApplication3::testsignal, qobj,&obj::testslot); //连接信号和槽emit testsignal();          //触发信号
}void obj::testslot()
{   qDebug() << "obj::testslot()";   }QtWidgetsApplication3::~QtWidgetsApplication3()
{}obj::obj(QObject* parent)
{}

 运行效果:

(2)信号和槽的五种写法与使用方式

(3)信号和槽之间的关系:

1、信号的参数类型必须与槽函数参数的类型相对应

signals:      //声明信号void testsignal(int);public slots: //声明槽void testslot(int);emit testsignal(100);  //触发信号

2、信号的参数个数大于等于槽函数的参数个数

signals:      //声明信号void testsignal(int,int);public slots: //声明槽void testslot(int);emit testsignal(100,100);  //触发信号

3、信号和槽函数之间的关系是多对多,信号也可以 连接到另一个信号上

signals:    //声明信号void testsignal(int);
public slots: //声明槽void testslot(int);
public slots: //声明槽void testslot2(int);QObject::connect(this,&QtWidgetsApplication3::testsignal, qobj,&obj::testslot); //连接信号和槽QObject::connect(this,&QtWidgetsApplication3::testsignal, qobj,&obj::testslot2); //连接信号和槽emit testsignal(100);  //触发信号

4、信号和槽的连接机制原理:通过QObject::connect来实现的

QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot);
//在上述代码中,sender对象的signal信号与receiver对象的slot槽函数被连接起来。

5、信号和槽的连接类型:

  • 直接连接(Direct Connection):这种连接方式类似于自动连接,但是即使在不同线程中也会立即调用槽函数。需要注意的是,这种方式可能导致竞态条件,因为它绕过了事件队列,所以使用时需要特别小心。
  • 队列连接(Queued Connection):在这种模式下,信号的发射不会立即导致槽函数的执行。相反,信号会被放入事件队列中,在下一个事件循环开始时才执行槽函数。这种方式常用于跨线程通信,因为可以避免直接从非GUI线程中调用可能会修改GUI组件的方法。
  • 自动连接(Auto Connection):这是默认的连接方式。当信号被发射时,Qt会立即调用相关的槽函数。这种方式适用于大多数情况,因为它是最快的方式,并且不需要额外的线程同步机制。
//直接连接
connect(button, &QPushButton::clicked, this, &MyWidget::handleClick, Qt::DirectConnection);
//队列连接
connect(button, &QPushButton::clicked, this, &MyWidget::handleClick, Qt::QueuedConnection);
//自动连接
connect(button, &QPushButton::clicked, this, &MyWidget::handleClick);

6、信号发射原理

emit mySignal(data);
//在上述代码中,当调用emit mySignal(data);时,所有连接到mySignaal的槽函数都会被调用。

7、槽函数调用过程

当一个信号被发射时,Qt负责按连接顺序调用与该信号连接的所有槽函数。

8、信号发射与线程

  • 信号可以安全地跨线程发射,如果信号接收者位于不同线程,Qt会自动将信号的处理放入目标线程的事件循环中,确保线程安全。
  • 信号的发射和槽的执行会自动适应线程间的通信机制,通过Qt的事件循环和消息队列机制来实现。
  • 线程安全:Qt的跨线程信号和槽机制是线程安全的,开发者无需担心常见的多线程问题,如竞态条件和死锁。
  • 自动同步:Qt处理所有线程间的通信细节,确保数据在线程间传递时的完整性和一致性。

7、信号和槽异步调用

当信号和槽位于不同线程时,Qt使用事件循环来实现异步调用。信号的发射将产生一个事件,该事件被放入目标线程的事件队列中。当事件循环处理到这个事件时,与之关联的槽函数被调用。

8、事件队列的角色

事件队列在信号和槽的跨线程通信中起着至关重要的作用。每个线程都有自己的事件队列和事件循环。当一个线程向另一个线程发出信号时,这个信号被封装成一个事件,然后被加入接收线程的事件队列。这确保了即使在高度并发的环境下,槽函数的执行也是线程安全的。

三、类型信息

Q_OBJECT 宏使得类可以通过 QMetaObject获取详细的运行时类型信息。这些信息包括类名、父类、信号、槽、属性等。

QtWidgetsApplication4.h

#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication4.h"
#include <QMetaObject>   //获取元对象
#include <QMetaMethod>   //信号与槽
#include <QMetaProperty> //属性
#include <QDebug>
#include <QObject>class QtWidgetsApplication4 : public QMainWindow
{Q_OBJECT
public:QtWidgetsApplication4(QWidget *parent = nullptr);~QtWidgetsApplication4();
private:Ui::QtWidgetsApplication4Class ui;
signals:void mysignal(int); //设置类的信号
private slots: void myslot(int);   //设置类的槽
private:int myProperty=false;
};

QtWidgetsApplication4.cpp

#include "QtWidgetsApplication4.h"QtWidgetsApplication4::QtWidgetsApplication4(QWidget *parent): QMainWindow(parent)
{ui.setupUi(this);//获取元对象const QMetaObject *metaObject = this->metaObject();//打印类名qDebug() << metaObject->className();//打印所有信号qDebug() << "Signals:";for (int i = 0; i < metaObject->methodCount(); i++){QMetaMethod  method = metaObject->method(i);qDebug() << method.name();}//打印所有槽qDebug() << "Slots:";for (int i = 0; i < metaObject->methodCount(); i++){QMetaMethod  method = metaObject->method(i);if (method.methodType() == QMetaMethod::Slot)qDebug() << method.name();}//打印所有属性qDebug() << "Properties:";for (int i = 0; i < metaObject->propertyCount(); i++){QMetaProperty property = metaObject->property(i);qDebug() << property.name();}
}QtWidgetsApplication4::~QtWidgetsApplication4()
{}void QtWidgetsApplication4::myslot(int)
{}

运行效果:

 四、动态设置属性

在QT中,动态属性设置的添加与修改,可以应用于数据绑定、状态管理、主题样式、事件处理等;例如:可以将 UI 控件的属性与模型数据绑定,这样当模型数据发生变化时,UI 控件的属性会自动更新。

QtWidgetsApplication5.cpp

#include "QtWidgetsApplication5.h"QtWidgetsApplication5::QtWidgetsApplication5(QWidget *parent): QMainWindow(parent)
{ui.setupUi(this);//获取当前对象的元对象const QMetaObject *metaObject = this->metaObject();//打印类名qDebug() << metaObject->className();//动态设置属性this->setProperty("dynamicProperty",QVariant(42));//动态获取属性QVariant value = this->property("dynamicProperty");qDebug() << "dynamicProperty:" << value.toInt();//检查属性是否存在QVariant checkValue =this->property("dynamicProperty");if (checkValue.isValid()) { qDebug() << "Property exists and its value is:" << checkValue.toInt(); }else { qDebug() << "Property does not exist."; }//修改属性this->setProperty("dynamicProperty", QVariant(100));//获取修改后的属性值value = this->property("dynamicProperty");qDebug() << "Modified dynamic property value:" << value.toInt();//删除属性this->setProperty("dynamicProperty",QVariant());checkValue = this->property("dynamicProperty");if (checkValue.isValid()) {qDebug() << "Property exists and its value is:" << checkValue.toInt();}else {qDebug() << "Property has been 'deleted'.";}
}QtWidgetsApplication5::~QtWidgetsApplication5()
{}

QtWidgetsApplication5.h

#pragma once#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication5.h"
#include <QMetaObject>   //获取元对象
#include <QMetaMethod>   //信号与槽
#include <QMetaProperty> //属性
#include <QDebug>class QtWidgetsApplication5 : public QMainWindow
{Q_OBJECT
public:QtWidgetsApplication5(QWidget *parent = nullptr);~QtWidgetsApplication5();
private:Ui::QtWidgetsApplication5Class ui;
};

运行效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/446725.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【华为】配置BGP协议

边界网关协议BGP是一种实现自治系统AS之间的路由可达&#xff0c;并选择最佳路由的距离矢量路由协议。BGP在不同自治系统之间进行路由转发&#xff0c;分为EBGP&#xff08;外部边界网关协议&#xff09;和IBGP&#xff08;内部边界网关协议&#xff09;两种情况。 [A]in g0/0/…

自动泊车变自动撞车?高速连接器如何助力智驾安全

当ADAS成为人们行车过程中的常伴辅助&#xff0c;颠覆人类驾驶方式的无人驾驶何时才能到来&#xff1f; 今年上半年&#xff0c;搭载了L2级辅助驾驶功能的新能源汽车渗透率达到了66.4%。自动驾驶领赛道作为新能源汽车智能化竞演中的“嫡赛道”&#xff0c;有股要席卷整个市场的…

执行vue create XXX报错The operation was rejected by your operating system

创建项目&#xff1a; vue create my-project 报错&#xff1a; npm ERR! code EPERM npm ERR! syscall open npm ERR! path D:\Program Files\nodejs\node_cache\_cacache\tmp\5d2a6f8e npm ERR! errno -4048 npm ERR! Error: EPERM: operation not permitted, open D:\Pro…

macOS Sequoia 15.0.1

macOS Sequoia 推出了一系列新功能&#xff0c;可助你在 Mac 上提高生产力和创造力。通过最新连续互通功能 iPhone 镜像&#xff0c;你可以在 Mac 上访问整个 iPhone。轻松平铺窗口快速打造理想工作空间&#xff0c;还可查看通过演讲者前置演示时即将共享的内容。经过重大更新的…

到底大模型有什么用呢?一文了解什么是大模型?

大模型是指具有大规模参数和复杂计算结构的机器学习模型。本文从大模型的基本概念出发&#xff0c;对大模型领域容易混淆的相关概念进行区分&#xff0c;并就大模型的发展历程、特点和分类、泛化与微调进行了详细解读&#xff0c;供大家在了解大模型基本知识的过程中起到一定参…

探索 Python 装饰器的新境界:wrapt 库的神秘力量

文章目录 探索 Python 装饰器的新境界&#xff1a;wrapt 库的神秘力量背景&#xff1a;为何选择 wrapt&#xff1f;wrapt 是什么&#xff1f;如何安装 wrapt&#xff1f;简单的 wrapt 库函数使用方法创建简单装饰器保持元信息处理参数传递 场景应用&#xff1a;wrapt 的实际用例…

闭着眼学机器学习——决策树分类

引言&#xff1a; 在正文开始之前&#xff0c;首先给大家介绍一个不错的人工智能学习教程&#xff1a;https://www.captainbed.cn/bbs。其中包含了机器学习、深度学习、强化学习等系列教程&#xff0c;感兴趣的读者可以自行查阅。 1. 算法介绍 决策树是一种常用的机器学习算法…

详解Java之lambda

目录 lambda 引入 语法 函数式接口 lambda表达式的使用 语法精简&#xff1a; 代码示例&#xff1a; 变量捕获 局部变量捕获 成员变量捕获 lambda在集合中的使用 lambda的优缺点 lambda 引入 Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表…

基于SSM的日常饮食健康推荐系统开发

文未可获取一份本项目的java源码和数据库参考。 课题的研究目的和意义 随着互联网的普及与通信技术的发展&#xff0c;现今人们可以通过各种方式在任何时间与地点访问网络&#xff0c;生活之中很多事情可以通过网络足不出户便可实现&#xff0c;例如通过网络购物、缴纳水电费…

短链接在线工具免费的哪个好?

目前市面上的很多短链接都不能用了&#xff0c;这类工具虽然技术含量不算高&#xff0c;但是需要长时间的持续维护&#xff0c;很多个人开发者的平台就坚持不下去了&#xff0c;愿意继续的&#xff0c;基本都是收费了。 所以&#xff0c;今天向大家推荐几款目前市面上很好用的…

五、UI弹窗提示

一、制作弹窗UI 二、创建脚本 1、继承WindowRoot&#xff08;UI基类&#xff09; 获取UI上面的组件 2、初始化 将这个文本失活 3、写一个提示出现的方法 这个派生类中&#xff0c;继承了基类的两个方法&#xff0c;设置显示和设置文本 对应基类的这两个方法 将动画赋值给动…

基于django的代理商订单管理系统

基于Django的代理商订单管理系统——高效助力代理商管理 在如今企业业务日益复杂的环境下&#xff0c;如何高效地管理代理商订单成为不可或缺的环节。我们推出了一款基于Django框架的代理商订单管理系统&#xff0c;专为企业的订单管理及返利控制设计&#xff0c;为企业与代理…

Jenkins pipeline语法笔记

Jenkins pipeline 简介Jenkins Pipeline 优势DSL 是什么 pipeline支持两种语法&#xff1a;声明式pipeline语法&#xff1a;Pipelineagent Pipeline 声明式语法DeclarativeenvironmentoptionsparameterstriggerstoolsinputwhenParallel Pipeline Scripted语法创建一个简单的 Pi…

ArrayList和顺序表(上)

1. ArrayList的介绍 在介绍ArrayList之前,我们需要认识一下线性表和顺序表 线性表: 是n个具有相同特性的数据元素的有限序列.常见的线性表:顺序表,链表,栈,队列... 线性表在逻辑上是线性结构,也就是一条连续的直线.但是在物理结构上不一定是连续的,线性表在物理上存储的时候,常…

降噪效果好的头戴式耳机有哪些?四大值得入手的百元降噪耳机盘点

在嘈杂的现代生活中&#xff0c;寻找一片属于自己的宁静空间已成为许多人的追求&#xff0c;头戴式降噪耳机凭借其出色的隔音效果和舒适的佩戴体验&#xff0c;成为了众多消费者的首选&#xff0c; 在通勤路上的喧嚣&#xff0c;还是办公室内的嘈杂&#xff0c;降噪效果好的头…

jmeter在beanshell中使用props.put()方法的注意事项

在jmeter中&#xff0c;通常使用beanshell去处理一些属性的设置和获取的操作&#xff0c;而这些操作也是有一定的规则的。 1. 设置属性时&#xff0c;在属性名上要加双引号&#xff0c;这代表它不是一个需要用var去声明的变量 这种设置属性的方式才是有效可行的&#xff0c;在…

使用HTML、CSS和JavaScript创建图像缩放功能

使用HTML、CSS和JavaScript创建图像缩放功能 在这篇博客文章中&#xff0c;我们将介绍如何使用HTML、CSS和JavaScript创建一个简单的图像缩放功能。这个功能可以增强用户体验&#xff0c;让访问者在点击图像时查看更大的版本。 效果 步骤1&#xff1a;设置HTML结构 首先&…

Pytest基于fixture的参数化及解决乱码问题

我们知道&#xff0c;Pytest是Python技术栈下进行自动化测试的主流测试框架。支持灵活的测试发现、执行策略&#xff0c;强大的Fixture夹具和丰富的插件支持。 除了通过pytest的parametrize标签进行参数化外&#xff0c;我们通过fixture的param参数也可以比较方便地实现参数化…

java对接GPT 快速入门

统一对接GPT服务的Java说明 当前&#xff0c;OpenAI等GPT服务厂商主要提供HTTP接口&#xff0c;这使得大部分Java开发者在接入GPT时缺乏标准化的方法。 为解决这一问题&#xff0c;Spring团队推出了Spring AI &#xff0c;它提供了统一且标准化的接口来对接不同的AI服务提供商…

记一次有趣的发现-绕过堡垒机访问限制

前言 在某一次对设备运维管理的时候&#xff0c;发现的某安全大厂堡垒机设备存在绕过访问限制的问题&#xff0c;可以直接以低权限用户访问多个受控系统&#xff0c;此次发现是纯粹好奇心驱使下做的一个小测试压根没用任何工具。因为涉及到了很多设备和个人信息&#xff0c;所以…