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

Qt学习之路(51): QByteArray和QVariant

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://devbean.blog.51cto.com/448512/276235

前面我们在介绍QString的最后部分曾经提到了QByteArray这个类。现在我们就首先对这个类进行介绍。

QByteArray具有类似与QString的API。它也有相应的函数,比如left(), right(), mid()等。这些函数不仅名字和QString一样,而且也具有几乎相同的功能。QByteArray可以存储原生的二进制数据和8位编码的文本数据。这句话怎么理解呢?我们知道,计算机内部所有的数据都是以0和1的形式存储的。这种形式就是二进制。比如一串0、1代码:1000,计算机并不知道它代表的是什么,这需要由上下文决定:它可以是整数8,也可以是一个ARGB的颜色(准确的说,整数8的编码并不是这么简单,但我们姑且这个理解吧)。对于文件,即便是一个文本文件,读出时也可以按照二进制的形式读出,这就是二进制格式。如果把这些二进制的0、1串按照编码解释成一个个字符,就是文本形式了。因此,QByteArray实际上是原生的二进制,但是也可以当作是文本,因此拥有文本的一些操作。但是,我们还是建议使用QString表示文本,重要的原因是,QString支持Unicode。

为了方便期间,QByteArray自动的保证“最后一个字节之后的那个位”是'\0'。这就使得 QByteArray可以很容易的转换成const char *,也就是上一章节中我们提到的那两个函数。同样,作为原生二进制存储,QByteArray中间也可以存储'\0',而不必须是'\0'在最后一位。

在有些情况下,我们希望把数据存储在一个变量中。例如,我有一个数组,既希望存整数,又希望存浮点数,还希望存 string。对于Java来说,很简单,只要把这个数组声明成Object[]类型的。这是什么意思呢?实际上,这里用到的是继承。在Java 中,int和float虽然是原生数据类型,但是它们都有分别对应一个包装类Integer和Float。所有这些Integer、Float和 String都是继承于Object,也就是说,Integer、Float和String都是一个(也就是is-a的关系)Object,这样,Object的数组就可以存储不同的类型。但是,C++中没有这样一个Object类,原因在于,Java是单根的,而C++不是。在Java中,所有类都可以上溯到Object类,但是C++中没有这么一个根。那么,怎么实现这么的操作呢?一种办法是,我们都存成string类,比如int i=10,我就存"10"字符串。简单的数据类型固然可以,可复杂一些的呢?比如一个颜色?难道要把ARGB所有的值都转化成string?这种做法很复杂,而且失去了C++的类型检查等好处。于是我们想另外的办法:创建一个Object类,这是一个“很大很大的”类,里面存储了几乎所有的数据类型,比如下面的代码:

1. class Object
2. {
3. public:
4. int intValue;
5. float floatValue;
6. string stringValue;
7. };

这个类怎么样?它就足以存储int、float和string了。嗯,这就是我们的思路,也是Qt的思路。在Qt中,这样的类就是QVariant。

QVariant可以保存很多Qt的数据类型,包括QBrush、QColor、QCursor、 QDateTime、QFont、QKeySequence、QPalette、QPen、QPixmap、QPoint、QRect、QRegion、 QSize和QString,并且还有C++基本类型,如int、float等。QVariant还能保存很多集合类型,如 QMap<QString, QVariant>, QStringList和QList<QVariant>。item view classes,数据库模块和QSettings都大量使用了QVariant类,,以方便我们读写数据。

QVariant也可以进行嵌套存储,例如

1. QMap<QString, QVariant> pearMap;
2. pearMap["Standard"] = 1.95;
3. pearMap["Organic"] = 2.25;
4.
5. QMap<QString, QVariant> fruitMap;
6. fruitMap["Orange"] = 2.10;
7. fruitMap["Pineapple"] = 3.85;
8. fruitMap["Pear"] = pearMap;

QVariant被用于构建Qt Meta-Object,因此是QtCore的一部分。当然,我们也可以在GUI模块中使用,例如

1. QIcon icon("open.png");
2. QVariant variant = icon;
3. // other function
4. QIcon icon = variant.value<QIcon>();

我们使用了value<T>()模版函数,获取存储在QVariant中的数据。这种函数在非GUI数据中同样适用,但是,在非GUI模块中,我们通常使用toInt()这样的一系列to...()函数,如toString()等。

如果你觉得QVariant提供的存储数据类型太少,也可以自定义QVariant的存储类型。被 QVariant存储的数据类型需要有一个默认的构造函数和一个拷贝构造函数。为了实现这个功能,首先必须使用Q_DECLARE_METATYPE() 宏。通常会将这个宏放在类的声明所在头文件的下面:

1. Q_DECLARE_METATYPE(BusinessCard)

然后我们就可以使用:

1. BusinessCard businessCard;
2. QVariant variant = QVariant::fromValue(businessCard);
3. // ...
4. if (variant.canConvert<BusinessCard>()) {
5. BusinessCard card = variant.value<BusinessCard>();
6. // ...
7. }

由于VC 6的编译器限制,这些模板函数不能使用,如果你使用这个编译器,需要使用qVariantFromValue(), qVariantValue<T>()和qVariantCanConvert<T>()这三个宏。

如果自定义数据类型重写了<<和>>运算符,那么就可以直接在QDataStream中使用。不过首先需要使用qRegisterMetaTypeStreamOperators<T>().宏进行注册。这就能够让QSettings使用操作符对数据进行操作,例如

1. qRegisterMetaTypeStreamOperators<BusinessCard>("BusinessCard");

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/276235

相关文章:

  • 我该如何奋斗?
  • Qt学习之路(50): QString
  • 原创:C语言贪吃蛇代码
  • Qt学习之路(49): 通用算法
  • 【转】解决:SecureCRT在Linux下vim显示utf-8编码的文件乱码
  • Qt学习之路(47): 自定义Model之三
  • 用vc++做滚动条控件
  • Qt学习之路(48): 自定义委托
  • 9520个大气笔刷!902个无缝叠加图案!!770个质感纹理!!!
  • Qt学习之路(46): 自定义model之二
  • 解决EntityFramework数据库无法自动迁移解决方法
  • Qt学习之路(45): 自定义model之一
  • 编译原理-词法分析器(DFA,C语言描述,可分析C/C++词法)
  • SQL 表操作
  • Qt学习之路(44): QSortFilterProxyModel
  • django开发-定时任务的使用
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • ES6系列(二)变量的解构赋值
  • EventListener原理
  • java8 Stream Pipelines 浅析
  • JAVA并发编程--1.基础概念
  • k8s 面向应用开发者的基础命令
  • KMP算法及优化
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Node项目之评分系统(二)- 数据库设计
  • SpiderData 2019年2月13日 DApp数据排行榜
  • SQLServer之创建数据库快照
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue2 SSR 的优化之旅
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 笨办法学C 练习34:动态数组
  • 警报:线上事故之CountDownLatch的威力
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 一道面试题引发的“血案”
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • C# - 为值类型重定义相等性
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $forceUpdate()函数
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (zt)最盛行的警世狂言(爆笑)
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (七)理解angular中的module和injector,即依赖注入
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core WebAPI中封装Swagger配置