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.h

#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication3.h"
#include <QObject> //包含头文件,以使用信号槽class QtWidgetsApplication3 : public QMainWindow
{//启用Qt的元对象系统,允许使用信号和槽等特性Q_OBJECTpublic: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.mzph.cn/pingmian/55782.shtml

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

相关文章

java反序列化之CommonCollections6利⽤链的学习

一、源起 前文学习CC1链和URLDNS链的学习&#xff0c;同时学习过程中知道cc1受jdk版本的限制&#xff0c;故而进一步分析cc6链的利用过程&#xff0c;这个利用链不受jdk版本的限制&#xff0c;只要commons collections小于等于3.2.1&#xff0c;都存在这个漏洞。 ps&#xff1…

运用MinIO技术服务器实现文件上传——在Linux系统上安装和启动(一)

# MinIO 单机版环境搭建详解 ## 1. 简介 随着大数据时代的到来&#xff0c;数据存储的需求日益增大&#xff0c;如何有效地存储和管理大规模的非结构化数据成为许多企业和开发者面临的挑战。MinIO 作为一个高性能、分布式对象存储系统&#xff0c;致力于为用户提供简单、快速…

Linux 6.11版本发布

Linux 6.11版本的发布是Linux社区的一个重要里程碑&#xff0c;它不仅在实时计算、性能优化方面取得了显著进展&#xff0c;还在安全性上迈出了关键一步。 一、实时计算与性能优化 1.io_uring子系统支持 Linux 6.11引入了io_uring子系统的增强功能&#xff0c;特别是支持了b…

SpringBoot中间件Docker

Docker&#xff08;属于C/S架构软件&#xff09; 简介与概述 1.Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux …

【ubuntu】Ubuntu20.04安装中文百度输入法

1.download 百度Linux输入法-支持全拼、双拼、五笔 2.unzip unzip Ubuntu_Deepin-fcitx-baidupinyin-64.zip 3.setting 3.1 setting fcitx sudo apt install aptitude sudo aptitude install fcitx-bin fcitx-table fcitx-config-gtk fcitx-frontend-all sudo aptitude in…

Cocos_鼠标滚轮放缩地图

文章目录 前言一、环境二、版本一_code2.分析类属性方法详细分析详细分析onLoad()onMouseWheel(event)详细分析 总结 前言 学习笔记&#xff0c;请多多斧正。 一、环境 通过精灵rect放置脚本实现鼠标滚轮放缩地图。 二、版本一_code import { _decorator, Component, Node }…

使用Buildpacks构建Docker镜像

## 使用Buildpacks构建Docker镜像 ![](../assets/运维手册-Buildpacks-Buildpacks.io.png) ### Buildpacks简介 与Dockerfile相比&#xff0c;Buildpacks为构建应用程序提供了更高层次的抽象。具体来说&#xff0c;Buildpacks&#xff1a; * 提供一个平衡的控制&#xff0c;…

【Python】Conda离线执行命令

以下链接证明了想要离线使用conda命令的方法 启用离线模式 — Anaconda documentation 基本上大部分的命令都会提供网络选项 例如creat命令 conda create — conda 24.7.1 文档 - Conda 文档

多区域OSPF路由协议

前言 之前也有过关于OSPF路由协议的博客&#xff0c;但都不是很满意&#xff0c;不是很完整。现在也是听老师讲解完OSPF路由协议&#xff0c;感触良多&#xff0c;所以这里重新整理一遍。这次应该是会满意的 一些相关概念 链路状态 链路指路由器上的一个接口&#xff0c;链路状…

ubuntu的useradd和adduser命令

useradd vs adduser 1. useradd 类型&#xff1a;Linux 命令。功能&#xff1a;用于创建新用户&#xff0c;但不会自动创建用户的主目录和密码。参数&#xff1a; -c&#xff1a;添加备注。-d&#xff1a;指定用户主目录。-e&#xff1a;设置用户有效期。-f&#xff1a;设置密…

ChatGLM详解

一 ChatGLM定义 ChatGLM是由清华技术成果转化的公司智谱AI发布的开源的、支持中英双语问答的对话语言模型系列&#xff0c;并针对中文进行了优化&#xff0c;该模型基于General Language Model&#xff08;GLM&#xff09;架构构建&#xff0c;ChatGLM是一款基于人工智能技术的…

Oracle架构之物理存储之审计文件

文章目录 1 审计文件&#xff08;audit files&#xff09;1.1 定义1.2 查看审计信息1.3 审计相关参数1.4 审计的类型1.4.1 语句审计1.4.2 权限审计1.4.3 对象审计1.4.4 细粒度的审计 1.5 与审计相关的数据字典视图 1 审计文件&#xff08;audit files&#xff09; 1.1 定义 审…

C++面试速通宝典——9

170. 简述数组和指针的区别&#xff1f; ‌‌‌‌  答&#xff1a;数组要么在静态存储区被创建&#xff08;如全局数组&#xff09;&#xff0c;要么在栈上被创建。指针可以随时指向任意类型的内存块。 1. 修改内容上的区别 char a[] “hello”; a[0] ‘X’; char * p …

毕设分享 基于协同过滤的电影推荐系统

文章目录 0 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

【Android 源码分析】Activity生命周期之onStop-2

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

信息安全工程师(28)机房安全分析与防护

前言 机房安全分析与防护是一个复杂而细致的过程&#xff0c;涉及到物理安全、环境控制、电力供应、数据安全、设备管理、人员管理以及紧急预案等多个方面。 一、机房安全分析 1. 物理安全威胁 非法入侵&#xff1a;未经授权的人员可能通过门窗、通风口等进入机房&#xff0c;…

【LeetCode】每日一题 2024_10_10 优质数对的总数 I(暴力/哈希)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;优质数对的总数 I 代码与解题思路 简单题先暴力~ 直接对着题意模拟即可&#xff0c;力扣上只要是标着简单标签的题目&#xff0c;不用犹豫&#xff0c;直接对他使用暴力吧&#xff01; …

亮度(luminance)

亮度&#xff08;luminance&#xff09;的单位是坎德拉每平方米&#xff08;cd/m&#xff09;。它是用来描述光源或物体表面发出的光在某个方向上的亮度程度。亮度可以简单理解为人眼感知的物体表面在某一特定方向上发出的光强。 亮度的理解&#xff1a; 亮度的概念&#xff…

LabVIEW混合控制器质量检测

随着工业自动化水平的提高&#xff0c;对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域&#xff0c;传统的质量检测方法已无法满足现代工业的高要求。因此&#xff0c;开发一套自动化、精确、可扩展的混合控制器质量检测平台成…

【Linux】常用系统命令

Linux 系统中有许多常用的命令&#xff0c;适用于不同的任务和场景。以下是一些基础且常用的 Linux 命令&#xff1a; 1. **文件和目录操作** - ls&#xff1a;列出目录内容。 - cd&#xff1a;改变当前目录。 - pwd&#xff1a;打印当前工作目录。 - mkdir&#…