QT 5 同时使用Q_DECLARE_METATYPE(pointdata) 和继承 QObjectUserData
在Qt框架中,QObjectUserData
和 Q_DECLARE_METATYPE()
宏都与Qt的元对象系统有关,但它们的使用方式有一些特别的限制和兼容性问题。
-
关于
QObjectUserData
:QObjectUserData
是一个用来存储用户数据的类。在Qt中,每个QObject
可以存储一个QObjectUserData
指针数组,每个指针可以指向一个QObjectUserData
对象。- 这个类通常用于在不修改类定义的情况下,为对象附加额外的数据。
-
关于
Q_DECLARE_METATYPE()
:Q_DECLARE_METATYPE()
宏允许类型在Qt的元对象系统中使用,如在QVariant
中。使用这个宏可以让自定义类型通过QVariant
进行存储和传递。- 宏定义需要类型是完全定义的,且具有公共的默认构造函数、复制构造函数和析构函数。
兼容性问题:
- 由于
QObject
本身和继承自QObject
的任何类不能被复制,这意味着如果你的类继承自QObject
(或间接通过其他类继承),这个类就不能使用Q_DECLARE_METATYPE()
。因为QVariant
需要能够复制其存储的类型。 - 如果你的类仅仅继承自
QObjectUserData
并不包含QObject
的继承,理论上是可以使用Q_DECLARE_METATYPE()
的,只要你的类满足可以被复制的要求。但是,这种情况比较少见,因为QObjectUserData
的设计初衷是作为一种与QObject
相关的数据扩展。
结论:
- 如果你的类继承自
QObject
或包含QObject
的成员,则不能使用Q_DECLARE_METATYPE()
。 - 如果你的类仅继承自
QObjectUserData
并且符合可以被复制的条件(例如,提供了公共的构造函数和复制构造函数),那么使用Q_DECLARE_METATYPE()
是可能的。
QObject
本身以及任何从 QObject
继承的类都不能被复制。这是由 QObject
的设计决定的,主要出于以下几个原因:
-
信号与槽机制:
QObject
提供了一个强大的信号与槽机制,用于对象之间的通信。每个QObject
可以发射信号,这些信号可以被同一个对象或其他对象的槽函数接收。如果QObject
可以被复制,那么信号和槽的连接就可能会被意外复制,从而导致难以追踪的bug。 -
对象的唯一性:每个
QObject
可以有一个父对象和多个子对象。这种父子关系管理着对象之间的层次结构和生命周期。复制QObject
会复杂化这种父子关系,可能导致父对象和子对象在删除或移动时出现问题。 -
设计决策:为了保持对象间关系的清晰和简单,Qt设计者选择禁用
QObject
的复制构造函数和赋值运算符,使它们为私有成员。这样,任何试图复制QObject
或其派生类的操作都会在编译时被阻止。
因此,如果你需要在 Qt 中使用包含对象状态的类并希望通过 QVariant
来传递,你应该设计这些类为非 QObject
派生类,并确保它们可以安全地被复制和销毁。这样,你就可以使用 Q_DECLARE_METATYPE()
宏来注册你的类型。
“复制”指的是通过拷贝构造函数和拷贝赋值运算符来复制一个对象。在 QObject
的上下文中,以下是具体的含义:
-
拷贝构造函数:这是一个构造函数,它初始化一个新对象作为一个已存在对象的副本。在
QObject
的情况下,拷贝构造函数是被明确声明为删除的,这意味着你不能使用一个QObject
或其派生类的实例来直接初始化另一个实例。 -
拷贝赋值运算符:这是一个赋值运算符,它允许将一个对象的状态赋值到另一个已存在的对象上。对于
QObject
及其派生类,拷贝赋值运算符同样被声明为删除,这意味着你不能通过赋值将一个QObject
或其派生类的状态复制到另一个对象。
这种设计是为了防止对象之间的不当信号连接和复杂化的父子关系,确保 QObject
的对象模型保持简洁和一致。这也意味着在使用 Qt 框架时,应该避免设计需要复制 QObject
或其派生类的场景,而是通过指针和引用来管理对象的生命周期和关系。
这个示例程序主要演示了如何在 Qt 应用程序中创建和使用自定义数据类型 `PointData` 和 `Point`。程序通过结合使用 `Q_DECLARE_METATYPE`、`QObjectUserData`,以及 Qt 的属性和变量系统 (`QVariant`),展示了如何有效地管理和使用自定义数据结构。下面是对程序各部分功能的详细解释:
功能和目的
1.PointData` 类的定义与注册
- `PointData` 是一个简单的类,用于存储和操作二维坐标点(x, y)。
- 使用 `Q_DECLARE_METATYPE(PointData)` 宏声明这个类,使其可以被 Qt 的元类型系统识别。这是必要的步骤,以便 `PointData` 对象可以安全地存储在 `QVariant` 类型中,并在 Qt 的信号和槽系统中使用。
2. `Point` 类的定义
- `Point` 类继承自 `QObjectUserData`,允许它作为用户自定义数据被存储在任何 `QObject` 实例中。这为 `Point` 实例的存储提供了便利,尤其是在需要将额外数据附加到 `QObject` 对象上时。
3. 应用程序主函数的实现
- 元类型注册:通过 `qRegisterMetaType<PointData>()` 确保 `PointData` 类型被 Qt 系统识别,这是使用自定义类型与 `QVariant` 相互操作的前提。
- 使用 `QVariant` 管理自定义数据:创建 `PointData` 实例,并通过 `QVariant` 系统演示如何将自定义类型封装和解封,从而验证元类型的注册和使用。
- 使用 `QObjectUserData`创建 `Point` 实例,并将其作为用户数据附加到 `QObject` 对象上,然后从该对象中检索 `Point` 实例。这展示了如何在运行时动态地管理额外的对象信息。
总体目的
- 演示 Qt 的灵活性和功能:通过使用 `Q_DECLARE_METATYPE` 和 `QObjectUserData`,这个示例展示了 Qt 如何处理自定义类型的封装和传输,以及如何将额外的数据动态地附加到 `QObject` 实例。
- 教育和示范:代码提供了一个实际的例子,说明了如何在 Qt 应用程序中创建、管理和使用自定义数据类型,是学习 Qt 开发的有用资源。
通过这种方式,示例程序不仅展示了 Qt 的核心概念和功能,还提供了一个关于如何扩展 Qt 应用程序功能的实际案例,特别适用于那些需要在应用程序中处理复杂数据结构和进行高级数据管理的场景。
在 Qt 框架中,Q_DECLARE_METATYPE
宏用于注册一个自定义类型,使之可以使用 Qt 的元类型系统。这种注册使得该类型能够在 Qt 的一些高级特性中使用,如信号和槽系统、变量传递等。具体来说,使用 Q_DECLARE_METATYPE
之后,你的类型就可以安全地用于 QVariant
,这是 Qt 用于存储能够包含任何类型的通用容器。
功能和用途
当你声明 Q_DECLARE_METATYPE(PointData)
时,你允许 PointData
类型的对象被包装进 QVariant
对象。这样做有几个好处:
-
使用信号和槽:使得
PointData
类型可以安全地作为参数在信号和槽之间传递。没有注册的类型不能用于信号和槽系统中,除非它们是内置的 Qt 类型。 -
动态属性:允许你将
PointData
对象作为动态属性添加到任何QObject
派生类的实例中。 -
变体操作:可以在需要类型安全和灵活操作的场景下,将
PointData
存储和检索为QVariant
。这在需要将数据存储在通用容器中时非常有用,例如,在模型视图架构中传递自定义数据。
// pointdata.h
#ifndef POINTDATA_H
#define POINTDATA_H#include <QMetaType>class pointdata
{
public:int x;int y;pointdata();pointdata(int x, int y);int getX() const;int getY() const;void setX(int x);void setY(int y);
};Q_DECLARE_METATYPE(pointdata)#endif // POINTDATA_H
#include "pointdata.h"pointdata::pointdata(): x(0), y(0)
{}pointdata::pointdata(int x, int y): x(x), y(y)
{}int pointdata::getX() const
{return x;
}int pointdata::getY() const
{return y;
}void pointdata::setX(int x)
{this->x = x;
}void pointdata::setY(int y)
{this->y = y;
}
在 Qt 框架中,QObjectUserData
类是用于将用户数据附加到 QObject
类的实例上的基类。它提供了一个方便的方式来存储额外的、动态的信息与 QObject
相关联,而无需修改 QObject
的源代码或继承自 QObject
。
使用场景和目的
QObjectUserData
主要被设计用于在运行时向 QObject
实例添加自定义数据,而不改变其类定义。这对于如插件系统等需要在没有修改现有类的情况下扩展对象功能的场景特别有用。
基本概念
当你继承自 QObjectUserData
并创建自定义类时,你可以利用 Qt 对象系统的功能,将这个自定义类的实例存储为 QObject
的一部分。每个 QObject
可以存储多个 QObjectUserData
对象,每个对象都与一个唯一的整数键相关联。
// point.h
#ifndef POINT_H
#define POINT_H#include <QObjectUserData>
#include <QSharedPointer>
#include "pointdata.h"class Point : public QObjectUserData
{
public:pointdata data;public:Point();Point(int x, int y);int getX() const;int getY() const;void setX(int x);void setY(int y);QSharedPointer<Point> clone() const;
};#endif // POINT_H
#include "point.h"Point::Point() {}Point::Point(int x, int y): data(x, y)
{}int Point::getX() const
{return data.getX();
}int Point::getY() const
{return data.getY();
}void Point::setX(int x)
{data.setX(x);
}void Point::setY(int y)
{data.setY(y);
}QSharedPointer<Point> Point::clone() const
{return QSharedPointer<Point>::create(data.getX(), data.getY());
}
主函数:
- 注册
pointdata
类型为 Qt 元类型系统的一部分。这使得pointdata
类型可以被用于 Qt 的信号和槽机制,并能以类型安全的方式存储在QVariant
中。 - 创建一个
pointdata
实例并将其包装进QVariant
对象。这展示了如何使用自定义类型与QVariant
,以及如何从QVariant
中提取自定义类型的实例。使用QVariant
是 Qt 中管理泛型数据的常见方式。 - 使用
Point
类实例作为用户数据存储在QObject
中。这个示例演示了如何将自定义的用户数据附加到 Qt 对象,并在之后检索使用这些数据。这是利用QObjectUserData
实现的功能。
#include <QApplication>
#include <QDebug>
#include "Point.h"
#include "PointData.h"
#include "mainwindow.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);// Register PointData as a metatypeqRegisterMetaType<pointdata>("PointData");// Using PointDatapointdata pd(3, 4);QVariant var = QVariant::fromValue(pd);if (var.canConvert<pointdata>()) {pointdata extractedData = var.value<pointdata>();qDebug() << "PointData: x =" << extractedData.getX() << ", y =" << extractedData.getY();}// Using Point with QObjectUserDataQObject obj;Point *point = new Point(5, 6); // Create a Point instanceobj.setUserData(0, point); // Store the Point instance as user data in QObject// Retrieve and use the Point instance from QObjectPoint *retrievedPoint = static_cast<Point *>(obj.userData(0));if (retrievedPoint) {qDebug() << "Point: x =" << retrievedPoint->data.getX()<< ", y =" << retrievedPoint->data.getY();}MainWindow w;w.show();return a.exec();
}
输出:
07:05:33: Starting E:\WD\untitled85\build\Desktop_Qt_5_15_2_MSVC2019_64bit-Debug\debug\untitled85.exe...
PointData: x = 3 , y = 4
Point: x = 5 , y = 6
07:05:38: E:\WD\untitled85\build\Desktop_Qt_5_15_2_MSVC2019_64bit-Debug\debug\untitled85.exe 退出,退出代码: 0{1 ?} {2?}
相关文章:

QT 5 同时使用Q_DECLARE_METATYPE(pointdata) 和继承 QObjectUserData
在Qt框架中,QObjectUserData 和 Q_DECLARE_METATYPE() 宏都与Qt的元对象系统有关,但它们的使用方式有一些特别的限制和兼容性问题。 关于QObjectUserData: QObjectUserData 是一个用来存储用户数据的类。在Qt中,每个 QObject 可以…...

【MySQL进阶之路 | 高级篇】范式概述与第一范式
1. 范式简介 在关系型数据库中,关于数据表的设计的基本原则,规则就称为范式。可以理解为,一张数据表的设计结果需要满足的某种设计标准的级别。要想设计一个结构合理的关系型数据库,必须满足一定的范式。 范式的英文名是Normal …...

Open-TeleVision复现及机器人迁移
相关信息 标题 Open-TeleVision: Teleoperation with Immersive Active Visual Feedback作者 Xuxin Cheng1 Jialong Li1 Shiqi Yang1 Ge Yang2 Xiaolong Wang1 UC San Diego1 MIT2主页 https://robot-tv.github.io/链接 https://robot-tv.github.io/resources/television.pdf代…...

Notepad++换安装路径之后,右键打开方式报错:Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。的处理方法
把Notepad添加到右键打开方式,可以参考下面的3篇文章添加: https://blog.csdn.net/xiaoerbuyu1233/article/details/88287747 https://blog.csdn.net/qq_44000337/article/details/120277317 https://www.cnblogs.com/zhrngM/p/12899026.html 这里主要是…...

【Flutter 面试题】 使用成熟状态管理库的弊端有哪些?
【Flutter 面试题】 使用成熟状态管理库的弊端有哪些? 文章目录 写在前面口述回答补充说明写在前面 🙋 关于我 ,小雨青年 👉 CSDN博客专家,GitChat专栏作者,阿里云社区专家博主,51CTO专家博主。2023博客之星TOP153。 👏🏻 正在学 Flutter 的同学,你好! 😊 …...

Apache Commons技术详解
文章目录 简介官网链接原理基础使用Commons LangCommons Collections 高级使用Commons IOCommons Math 优缺点优点缺点 总结 简介 Apache Commons 是 Apache 软件基金会下的一个项目,旨在提供可重用的Java组件。这些组件覆盖了广泛的编程任务,从字符串处…...

怎样使用 Juicer tools 的 dump 命令将.hic文件转换为交互矩阵matrix计数文件 (Windows)
创作日志: 万恶的生信…一个scHiC数据集没有提供处理好的计数文件,需要从.hic转换。Github一个个好长的文档看了好久才定位到 juicer tools 的dump命令,使用起来比想象中简单。 一、下载Juicer tools 注意:使用Juicer tools的前提…...

【Docker】Docker Desktop - WSL update failed
问题描述 Windows上安装完成docker desktop之后,第一次启动失败,提示:WSL update failed 解决方案 打开Windows PowerShell 手动执行: wsl --set-default-version 2 wsl --update...

基于rsync\unlink 等一套本机备份跨机备份历史备份清理shell 脚本
一 摘要 本文主要介绍一套本地备份、跨机器备份、历史备份清理脚本,使用场景如数据库备份等 二 环境 linux 系列系统 基本都支持,个别命令可能需要微调。 2.1 实验环境 [rootlocalhost rsync]# cat /etc/centos-release CentOS Linux release 7.9.2…...

使用nginx实现一个端口和ip访问多个vue前端
前言:由于安全组要求,前端页面只开放一个端口,但是项目有多个前端,此前一直使用的是一个前端使用单独一个端口进行访问,现在需要调整。 需要实现:这里以80端口为例,两个前端分别是:p…...

Linux云计算 |【第一阶段】SERVICES-DAY5
主要内容: 源码编译安装、rsync同步操作、inotify实时同步、数据库服务基础 实操前骤:(所需tools.tar.gz与users.sql) 1.两台主机设置SELinnx和关闭防火墙 setenforce 0 systemctl stop firewalld.service //停止防火墙 sy…...

IP第一次综合实验
一、实验拓扑 二、实验要求 1、R6为ISP,接口IP地址均为公有地址,该设备只能配置地址之后不能冉对其进行任何配置 2、R1-R5为局域网,私有Ip地址192.168.1.0/24,请合理分配 3、R1、82、R4,各有两个环回IP地址;R5,R6各…...

Could not load dynamic library ‘cudart64_100.dll‘
python代码报错 Could not load dynamic library cudart64_100.dll; dlerror: cudart64_100.dll not found 2024-07-22 14:19:21.931639: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine…...

四大引用——强软弱虚
目录 一、强引用 二、软引用 三、弱引用 四、虚引用 一、强引用 强引用是在程序代码之中普遍存在的,类似于“Object obj new Object()”,obj变量引用Object这个对象,就叫做强引用。当内存空间不足,Java虚拟机宁愿抛出OutOfMe…...

MySQL--索引(2)
InnoDB 1.索引类型 主键索引(Primary Key) 数据表的主键列使用的就是主键索引。 一张数据表有只能有一个主键,并且主键不能为 null,不能重复。 在 mysql 的 InnoDB 的表中,当没有显示的指定表的主键时,InnoDB 会自动先检查表中是…...

JVM类加载机制详解
Java在运行期才对类进行加载到内存、连接、初始化过程。这使得Java应用具有极高的灵活性和拓展性,可以依赖运行期进行动态加载和动态连接。 主要加载哪些?Java中的数据类型分为基本数据类型和引用数据类型,基本数据类型由虚拟机预先定义&…...

【MATLAB实战】基于UNet的肺结节的检测
数据: 训练过程图 算法简介: UNet网络是分割任务中的一个经典模型,因其整体形状与"U"相似而得名,"U"形结构有助于捕获多尺度信息,并促进了特征的精确重建,该网络整体由编码器,解码器以及跳跃连接三部分组成。 编码器由…...

Elasticsearch基础(五):使用Kibana Discover探索数据
文章目录 使用Kibana Discover探索数据 一、添加样例数据 二、数据筛选 三、保存搜索 使用Kibana Discover探索数据 一、添加样例数据 登录Kibana。在Kibana主页的通过添加集成开始使用区域,单击试用样例数据。 在更多添加数据的方式页面下方,单击…...

爬取百度图片,想爬谁就爬谁
前言 既然是做爬虫,那么肯定就会有一些小心思,比如去获取一些自己喜欢的资料等。 去百度图片去抓取图片吧 打开百度图片网站,点击搜索xxx,打开后,滚动滚动条,发现滚动条越来越小,说明图片加载…...

HTTP 缓存
缓存 web缓存是可以自动保存常见的文档副本的HTTP设备,当web请求抵达缓存时,如果本地有已经缓存的副本,就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…...

设计模式实战:图形编辑器的设计与实现
简介 本篇文章将介绍如何设计一个图形编辑器系统,系统包括图形对象的创建、组合、操作及撤销等功能。我们将通过这一项目,应用命令模式、组合模式和备忘录模式来解决具体的设计问题。 问题描述 设计一个图形编辑器系统,用户可以创建并操作图形对象,将多个图形对象组合成…...

.NET 情报 | 分析某云系统添加管理员漏洞
01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失…...

vue检测页面手指滑动距离,执行回调函数,使用混入的语法,多个组件都可以使用
mixin.ts 定义滑动距离的变量和检测触摸开始的方法,滑动方法,并导出两个方法 sendTranslateX.value > 250 && sendTranslateY.value < -100是向上滑动,满足距离后执行回调函数func,并在一秒内不再触发,一…...

opencv 优势
OpenCV(开源计算机视觉库)是一个广泛使用的计算机视觉和机器学习软件框架。它最初由Intel开发,后来由Itseez公司维护,最终于2015年成为非营利组织OpenCV.org的一部分。OpenCV的目的是实现一个易于使用且高效的计算机视觉框架,支持实时视觉应用。 以下是关于OpenCV的一些关…...

1-如何挑选Android编译服务器
前几天,我在我的星球发了一条动态:入手洋垃圾、重操老本行。没错,利用业余时间,我又重新捣鼓捣鼓代码了。在接下来一段时间,我会分享我从服务器的搭建到完成Android产品开发的整个过程。这些东西之前都是折腾过的&…...

【JS逆向课件:第十六课:Scrapy基础2】
ImagePipeLines的请求传参 环境安装:pip install Pillow USER_AGENT Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36需求:将图片的名称和详情页中图片的数据进行爬取&a…...

使用 PowerShell 自动化图像识别与鼠标操作
目录 前言功能概述代码实现1. 引入必要的程序集2. 定义读取文件行的函数3. 定义加载图片的函数4. 定义查找小图像在大图像中的位置的函数5. 定义截取全屏的函数6. 定义模拟鼠标点击的函数7. 定义主函数 配置文件示例运行脚本结语全部代码提示打包exe 下载地址 前言 在日常工作…...

组队学习——支持向量机
本次学习支持向量机部分数据如下所示 IDmasswidthheightcolor_scorefruit_namekind 其中ID:1-59是对应训练集和验证集的数据,60-67是对应测试集的数据,其中水果类别一共有四类包括apple、lemon、orange、mandarin。要求根据1-59的数据集的自…...

【数据中心】数据中心的IP封堵防护:构建网络防火墙的基石
数据中心的IP封堵防护:构建网络防火墙的基石 引言一、理解IP封堵二、IP封堵的功能模块及其核心技术三、实施IP封堵的关键策略四、结论 引言 在当今高度互联的世界里,数据中心成为信息流动和存储的神经中枢,承载着企业和组织的大量关键业务。…...

LangChain的使用详解
一、 概念介绍 1.1 Langchain 是什么? 官方定义是:LangChain是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序,它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供…...