QVariant

篇一:

1、为什么需要用QVariant类型?

使用 QObject::property 函数可读取属性的值,使用 QObject::setProperty 函数可以设置属性
的值,但是属性有很多种类型,怎样使用 property 函数返回的属性值具有正确的类型呢?
=》为解决这个问题,使用了一个 QVariant 描述类型

2、 QVariant 类用于封装数据成员的类型及取值等信息, 该类类似于 C++共用体 union, 一个
QVariant 对象,一次只能保存一个单一类型的值。 该类封装了 Qt 中常用的类型,对于
QVariant 不 支 持 的 类 型 ( 比 如 用 户 自 定 义 类 型 ) , 则 需 要 使 用
Q_DECLARE_METATYPE( Type )宏进行注册(详见后文)。

注意: QVariant 没有 char 类型的构造函数,若使用 char 值会被转换为对应的 int 型。

QVariant v(1); //调用 QVariant(int )构造函数创建一个 QVariant 类型的对象,并把数值 1 保存到 v 中。
v=2.2; //调用 QVariant 的赋值运算符,把值 2 保存在 v 之中,因为 QVariant 是类似于共用体的类,因此同一时间只会保存一个值。

3、 QVariant 拥常用类型的单形参构造函数,因此可把这些常用类型转换为 QVariant 类型,
同时 QVariant 还重载了赋值运算符,因此可把常用类型的值直接赋给 QVariant 对象。注:
由 C++语法可知,单形参构造函数进行类型转换

4、获取 QVariant 对象存储的值的类型,可使用如下函数
 Type type() const
获取 QVariant 对象当前存储值的类型,类型以枚举 QMetaType::Type 的形式表示
 const char * typeName() const;
以字符串的形式返回 QVariant 对象存储的值的类型。若是无效类型则返回 0。
 const char* typeToName(int t);
把以枚举类型 QMetaType::Type 表示的类型以字符串的形式返回。若枚举值为
QMetaType::UnknownType 或不存在,则返回一个空指针。
 示例

QVariant v(1);
cout<<v.typeName()<<endl; //输出 int
cout<<v.typeToName(v.type())<<endl; //输出 int


5、获取和设置 QVariant 对象存储的值,可使用如下函数

 void setValue(const T& v);
把一个值的副本存储到 QVariant 对象中,若类型 T 是 QVariant 不支持的类型,则使用
QMetaType 来存储该值,若 QMetaType 也不能处理,则发生编译错误。注:若是用户
自定义类型则需要使用宏 Q_DECLARE_METATYPE(…)进行注册(详见后文)
 T value() const;
把存储的值转换为类型 T 并返回转换后的值,存储值本身不会被改变。若 T 是
QVariant 支持的类型,则该函数与 toInt、 toString 等函数功能完全相同。注:使用该
函数时需要使用尖括号指定 T 的类型,比如 xx.value<int>();
 T toT()
 其中 T 是某一类型,比如若 T 是 int,则该函数形式就为 int toInt()。
 该函数用于把存储的值转换为类型T并返回转换后的值,存储值本身不会被改变。
其中比较常用的是 toString 函数,该函数可把存储的值转换为 QString 形式,这样
便可以字符串的形式输出存储的值。
 注意:没有与自定义类型相对应的 toT 函数,比如 class C{};则没有 toC 函数,要
把存储的值转换为自定义类型,需要使用 value 函数,且还需对自定义类型注册。

示例: QVariant 类的使用

#include<QVariant>
#include <iostream>
using namespace std;
class C{}; //自定义类型
int main(int argc, char *argv[])
{
	QVariant v('a'); /*QVariant 没有专门的 char 构造函数,此处的字符 a 会被转换为 int 型,因此 v中存储的是数值 97,而不是字符 a 。 */
	cout<<v.value<int>()<<endl; //输出 97
	cout<<v.value<char>()<<endl; //输出 a,将 97 转换为 char 型,并输出转换后的值。
	cout<<v.toChar().toLatin1()<<endl; /*输出 a,原因同上,注意 toChar 返回的类型是 QChar 而不是 char。 */
	cout<<v.toString().toStdString()<<endl; /*输出 97,把存储在 v 中的值转换为 QString,然后以字符串形式输出。 */
	cout<<v.typeName()<<endl; //输出 int, 可见存储在 v 中的值的类型为 int
	cout<<v.typeToName(v.type())<<endl; /*输出 int,其中 type 返回存储值的枚举形式表示的类型,而typeToName 则以字符串形式显示该枚举值所表示的类型。 */
	
	char c='b';
	v.setValue(c);
	cout<<v.toString().toStdString()<<endl; //输出 b
	cout<<v.typeName()<<endl; /*输出 char,若是使用 QVariant 构造函数和直接赋值 char 型字符,此处会输出 int,这是 setValue 与他们的区别。 */
	C mc; //自定义类型 C 的对象 mc
	//QVariant v1(mc); //错误,没有相应的构造函数。
	QVariant v2;
	//v2=mc; //错误,没有与类型 C 匹配的赋值运算符函数。
	//v2.setValue(mc); //错误,自定义类型 C 未使用宏 Q_DECLARE_METATYPE 声明。
	
	return 0; 
}

篇二:

原文链接:https://blog.csdn.net/m0_73482095/article/details/135384060

一、QVariant的概述
QVariant是Qt中一个强大的变体类,提供了一种通用的方式来存储Qt对象及其他类的值,可以以类似于指针的方式存储任意类型的值。

由于QVariant是一个通用的类型,因此可以在不丢失语义的情况下存储几乎所有数据类型。作为一个变体类型,它支持自我描述、值类型检查和动态转换等特性,具有安全性和利用性。

它可以存储任何数据类型的值,并提供了一些方便的方法来转换这些值,同时也可以在Qt中使用信号和槽机制传递任何类型的数据。

QVariant 这个类型充当着最常见的数据类型的联合。QVariant 可以保存很多Qt的数据类型,包括QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、 QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize和QString,并且还有C++基本类型,如 int、float等。

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

Q_DECLARE_METATYPE(MyClass)

QVariant可以存储各种基本数据类型,如整数、浮点数、字符串、布尔值等,也可以存储自定义的数据类型,如QObject派生类、QPixmap等。
通过QVariant,可以方便地在Qt的不同组件之间传递数据,例如在不同的widget之间、在model/view框架中的数据传输、在信号和槽之间传递数据等。
QVariant类还提供了许多类型转换方法,如 toString()、toInt()、toDouble()等,这些方法可以将存储在QVariant中的值转换为不同的数据类型。
QVariant还提供了一些方法来判断其存储的值的类型,如type()、canConvert()等。

注意:千万别想着一步到位,QVariant存入的是什么类型,就将其转出什么类型!!!

二、QVariant的使用
1、QVariant的使用方法

QVariant var = 123;
int intValue = var.toInt(); // 将QVariant 转换为int类型
QString strValue = var.toString(); // 将QVariant 转换为QString类型
 
QVariant var;
var.setValue(42); // 存储整数 42
int i = var.toInt(); // 获取整数 42
 
var.setValue("Hello"); // 存储字符串 "Hello"
QString str = var.toString(); // 获取字符串 "Hello"
 
var.setValue(QColor(Qt::red)); // 存储 QColor
QColor color = var.value<QColor>(); // 获取 QColor


2、QVariant存储的类型判断

可以使用QVariant::type()函数,返回QVariant存储的值的类型,常用类型还可以使用相应的函数进行判断,例如:

QVariant var = "Hello, World";
if(var.type() == QVariant::String)
{
    qDebug() << "The QVariant stored a string value!";
}


 3、QVariant的类型转换

QVariant也支持用于显式转换的类型强制转换操作符。如果无法进行统一的操作,则转换失败,这时可以使用canConvert()函数进行转换:

QVariant var = 999;
if(var.canConvert())
{
    QString str = var.value();
}
 
QVariant var;
var.setValue(42);// 存储整数 42
 
if (var.canConvert<int>()) {
    int value = var.value<int>();  // 将 QVariant 对象转换为 int 类型
    qDebug() << "Value is: " << value;
} else {
    qDebug() << "Cannot convert to int!";
}


4、QVariant跟list之间的转换

任何的qt的类型要转成QVariant都需要先看下qt的帮助文档,查看该qt类型是否是一个基本的类型。例如:

QVariantList--实际就是--》QList<QVariant>
QVariantMap--实际就是--》QMap<QString, QVariant>
将一个QList转成一个QVariant类型:

Qlist<QVariant> list;
list<<QVariant::fromValue(90)<<QVariant::fromValue(89)<<QVariant::fromValue(67);
QVariant temp1;
temp1 = QVariant::fromValue(list);


5、放在 Qmap 当中使用:

QMap<QString, QVariant> qmap;
 
qmap["int"] = 2000;
qmap["double"] = 99.22;
qmap["string"] = "hello";
qmap["color"] = QColor(1,2,3);
 
qDebug() << qmap["int"] << qmap["int"].toInt();          // QVariant(int, 2000) 2000
qDebug() << qmap["double"] << qmap["double"].toDouble(); // QVariant(double, 99.22) 99.22
qDebug() << qmap["string"] << qmap["string"].toString();// QVariant(QString, "hello") "hello"
qDebug() << qmap["color"] << qmap["color"].value<QColor>();// QVariant(QColor, QColor(ARGB 1, 0.00392157, 0.00784314, 0.0117647)) QColor(ARGB 1, 0.00392157, 0.00784314, 0.0117647)

6、示例

支持的类型。对于QVariant支持的类型,可直接赋值,但是取值时,对于存入的是什么类型,取出也要为这个类型。

QVariant var;
var.setValue(12);
int data=var.toInt();
 
QVariant var=12;
int data=var.toInt();

对于不支持的C++基础数据类型,如 short  char,先通过toInt()转化为int类型,然后再将int转为其原本的数据类型。

 

//-------------------------------char--------------------------
//char -> QVariant
QVariant var='B';
qDebug()<<var;   //QVariant(int, 66)
 
 
// QVariant ->char
char channel=var.toInt();
 
//------------------------------short--------------------------
//short -> QVariant
short dataType=12;
QVariant var2=dataType;
qDebug()<<var2;      //QVariant(int, 12)
 
 
//QVariant -> short
short temp=(short)var2.toInt();


保存指针,感觉这个比较强大,也比较容易用到。如:

//保存
QVariant var=QVariant::fromValue((void*)event);
    
//获取
QPaintEvent* e=(QPaintEvent*)var.value<void*>();

   
三、QVariant存储自定义类型
QVariant可以存储自定义类型,只需要实现该类型的QDataStream插入提取操作符,然后调用Q_DECLARE_METATYPE()宏为该类型添加元数据:

class MyCustomType {
public:
    MyCustomType() {}
    MyCustomType(int i, QString str) : m_i(i), m_str(str) {}
 
    int m_i;
    QString m_str;
};
 
Q_DECLARE_METATYPE(MyCustomType);
 
QDataStream& operator<<(QDataStream &out, const MyCustomType &val) {
    out << val.m_i << val.m_str;
    return out;
}
 
QDataStream& operator>>(QDataStream &in, MyCustomType &val) {
    in >> val.m_i >> val.m_str;
    return in;
}
struct MyClass{
    int id;
    QString name;
};
Q_DECLARE_METATYPE(MyClass)
 
//存储数据
MyClass myClass;
myClass.id=0;
myClass.name=QString("LiMing");
 
data[0]=QString("ddd");
data[1]=123;
data[3]=QVariant::fromValue(myClass);
 
//获取数据
QString str=data.value(0).toString();
int val=data.value(1).toInt();
 
if(data[3].canConvert<MyClass>())
{
    MyClass myClass=data[3].value<MyClass>();
    int id=myClass.id;
    QString name=myClass.name;
}


结构体跟QVariant之间的转换

struct tytemp
{
    unsigned int target;
    unsigned int current;
};
Q_DECLARE_METATYPE(tytemp)
 
/*将结构体变成QVariant*/
QVariant temp1;
tytemp info;
info.target  = 90;
info.current = 100;
temp1 = QVariant::fromValue(info);
 
/*将QVariant变成结构体*/
tytemp tempinfo= temp1.value<tytemp>()


使用自定义的枚举作为参数

enum CusType
{
    TYPE_ONE = 1,
    TYPE_TWO = 2,
    TYPE_THREE = 3
};
Q_DECLARE_METATYPE(CusType)
 
void MainWindow::dealType()
{
    bool ok = false;
    //QVariant 转换为 QMeataType类型
    QVariant v1(123);
    qDebug() << "v1.typeName = " << v1.typeName() << ", canConvert<int>() = " << v1.canConvert<int>() << ", int  = " << v1.toInt(&ok) << ", ok = " << ok;
 
    QVariant v2("123");
    qDebug() << "v2.typeName = " << v2.typeName() << ", canConvert<int>() = " << v2.canConvert<int>() << ", int  = " << v2.toInt(&ok) << ", ok = " << ok;
 
    QVariant v3("123s");
    qDebug() << "v3.typeName = " << v3.typeName() << ", canConvert<int>() = " << v3.canConvert<int>() << ", int  = " << v3.toInt(&ok) << ", ok = " << ok;
 
    QString str3 = v3.value<QString>();
 
 
    QVariant v4(tr("123"));
    qDebug() << "v4.typeName = " << v4.typeName() << ", canConvert<int>() = " << v4.canConvert<int>() << ", int  = " << v4.toInt(&ok) << ", ok = " << ok;
 
    //自定义类型转换为 QVariant
    QVariant v5 = QVariant::fromValue(CusType::TYPE_ONE);
    qDebug() << "v5.typeName = " << v5.typeName() << ", canConvert<int>() = " << v5.canConvert<int>() << ", int  = " << v5.toInt(&ok) << ", ok = " << ok;
 
    //QVariant 转换为 自定义类型
    int i5 = v5.value<CusType>();
    qDebug() << "i5 = " << i5;  // i5=1
}

四、QVariant实现模板函数
QVariant还可以使用模板函数,实现任意类型转换:

template
inline QVariant toVariant(const T &value){
    return QVariant::fromValue(value);
}
使用方法:

int intValue = 123;
QVariant var1 = toVariant(intValue);
QVariant var2 = toVariant(QString("Hello, World"));

五、Json转为QVariant
QJsonObject转为QVariant,QVariant的构造函数是包含这些类型的。

    QJsonObject obj;
    obj.insert("name1","val1");
    obj.insert("name2","val2");
    obj.insert("name3","val3");
    QJsonArray arr;
    for(int i=0;i<5;i++)
        arr.append(i);
 
    obj.insert("name4",arr);
 
    QVariant var(obj);
 
 
//QJsonArray转为QVariant也是一样的
QVariant var2(arr);
 
//QJsonDocument转为QVariant
QVariant var3(QJsonDocument(obj));
 

一般为了方便本地调用,是直接将其转化为QVariantMap、QVariantHash或QVariantList

    QVariantList varList=arr.toVariantList();
    QVariantMap varMap=obj.toVariantMap();
    QVariantHash varHash=obj.toVariantHash();
使用的时候,直接调用

    qDebug()<<"varName_1="<<varMap.value("name1").toString();
    qDebug()<<"varName_2="<<varHash.value("name2").toString();
    for(int i=0;i<varList.count();i++){
        qDebug()<<varList.at(i).toInt();
    }

六、QVariant转为Json
这个只需要直接转换就可以了,前提是QVariant原本存入是类型就是Json

 const QJsonObject& _obj=var.toJsonObject();
若存入QVariant的类型是QVariantMap,那么就要多一个步骤了

    QVariant var4(obj.toVariantMap());
 
    const QJsonObject& __obj=QJsonObject::fromVariantMap(var4.toMap());
    qDebug()<<__obj.value("name1").toString();

七、QVariant转为QByteArray
看帮助文档,可以看出QVariant有方法可以直接转化成QByteArray,就直接将其转换为QByteArray,那么你拿到的QByteArray很可能就是空的~

我还是强调存入QVariant的是什么,你就要直接将其转换为什么,至于其他的类型,再继续转换。

若存入QVariant的是QJsonObject之类

qDebug()<<QJsonDocument(var.toJsonObject()).toJson(QJsonDocument::Compact);
若存入的是QVariant的是QVariantMap之类

qDebug()<<QJsonDocument::fromVariant(var4).toJson();
若存入的是QByteArray,那么什么好说的,当然直接转换,当然,出来的结果不是空的,除非你存入的是空的字节数组 

    QJsonDocument doc(obj);
    QVariant var5(doc.toJson(QJsonDocument::Compact));
    qDebug()<<var5.toByteArray();

八、应用场景

当您需要在Qt应用程序中传递不同类型的数据时,QVariant是非常实用的。以下是一些QVariant的实际使用场景:

        1、在不同的widget之间传递数据:在Qt的GUI编程中,widget是非常重要的组件。当您需要在不同的widget之间传递数据时,可以使用QVariant。例如,您可以将一个QVariant对象存储为QString,并将其传递给另一个widget。
        2、在model/view框架中传递数据:在Qt的model/view编程中,您可能需要在不同的model或view之间传递数据。QVariant非常适合这个任务。例如,您可以将一个QVariant对象存储为int,并将其传递给另一个model或view。
        3、在信号和槽之间传递数据:在Qt的信号和槽机制中,信号可以传递参数,这些参数可以是任何类型。使用QVariant,您可以轻松地将任何类型的数据传递给信号和槽。
        4、在存储和读取配置文件时使用:在Qt中,您可以使用QSettings类来存储和读取配置文件。当您需要存储不同类型的数据时,可以使用QVariant。例如,您可以将一个QVariant对象存储为QColor,并将其保存到配置文件中。

九、QVariant的性能分析
使用QVariant需要注意一些性能问题,QVariant不同于其他基础数据类型,因此不要将其用于高性能的应用程序或过于频繁的任务。

QVariant的存储需要占用一定的内存,因此在存储某些类型时应格外小心。理论上,QVariant存储的值的大小没有任何限制,但是如果存储的值太大,移动和复制操作可能会产生显著的开销。

QVariant本身的使用也可以产生性能影响,包括类型检查、值提取和转换等。因此,在性能要求高的场景中可以使用原始的基础数据类型来替代QVariant,或者使用QVariant来存储类型稳定的小型数据结构。

                        
原文链接:https://blog.csdn.net/m0_73482095/article/details/135384060

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值