有容乃大的QVariant之使用

一、简述

QVariant,是Qt中的一个变量类,属于Qt的底层核心之一,很多模块都是基于此类。可以支持N多的类型,具体支持多少,请看其类中定义的枚举:

enum Type {
    Invalid = QMetaType::UnknownType,
    Bool = QMetaType::Bool,
    Int = QMetaType::Int,
    UInt = QMetaType::UInt,
    LongLong = QMetaType::LongLong,
    ULongLong = QMetaType::ULongLong,
    Double = QMetaType::Double,
    Char = QMetaType::QChar,
    Map = QMetaType::QVariantMap,
    List = QMetaType::QVariantList,
    String = QMetaType::QString,
    StringList = QMetaType::QStringList,
    ByteArray = QMetaType::QByteArray,
    BitArray = QMetaType::QBitArray,
    Date = QMetaType::QDate,
    Time = QMetaType::QTime,
    DateTime = QMetaType::QDateTime,
    Url = QMetaType::QUrl,
    Locale = QMetaType::QLocale,
    Rect = QMetaType::QRect,
    RectF = QMetaType::QRectF,
    Size = QMetaType::QSize,
    SizeF = QMetaType::QSizeF,
    Line = QMetaType::QLine,
    LineF = QMetaType::QLineF,
    Point = QMetaType::QPoint,
    PointF = QMetaType::QPointF,
    RegExp = QMetaType::QRegExp,
    RegularExpression = QMetaType::QRegularExpression,
    Hash = QMetaType::QVariantHash,
    EasingCurve = QMetaType::QEasingCurve,
    Uuid = QMetaType::QUuid,
#if QT_CONFIG(itemmodel)
    ModelIndex = QMetaType::QModelIndex,
    PersistentModelIndex = QMetaType::QPersistentModelIndex,
#endif
    LastCoreType = QMetaType::LastCoreType,

    Font = QMetaType::QFont,
    Pixmap = QMetaType::QPixmap,
    Brush = QMetaType::QBrush,
    Color = QMetaType::QColor,
    Palette = QMetaType::QPalette,
    Image = QMetaType::QImage,
    Polygon = QMetaType::QPolygon,
    Region = QMetaType::QRegion,
    Bitmap = QMetaType::QBitmap,
    Cursor = QMetaType::QCursor,
    KeySequence = QMetaType::QKeySequence,
    Pen = QMetaType::QPen,
    TextLength = QMetaType::QTextLength,
    TextFormat = QMetaType::QTextFormat,
    Matrix = QMetaType::QMatrix,
    Transform = QMetaType::QTransform,
    Matrix4x4 = QMetaType::QMatrix4x4,
    Vector2D = QMetaType::QVector2D,
    Vector3D = QMetaType::QVector3D,
    Vector4D = QMetaType::QVector4D,
    Quaternion = QMetaType::QQuaternion,
    PolygonF = QMetaType::QPolygonF,
    Icon = QMetaType::QIcon,
    LastGuiType = QMetaType::LastGuiType,

    SizePolicy = QMetaType::QSizePolicy,

    UserType = QMetaType::User,
    LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type
};

太多了,让人瞠目结舌!

在这里插入图片描述

让我们来捋一捋,它除了支持int、double、bool等基本类型外,还支持QVariantMap、QVariantHash、QVariantList、QStringList等容器类型,还有一些类似QDateTime、QSize、QRect、QLine、QBitmap、QTransform、QIcon、QBrush、QColor、QFont等各种类型。

除此以外,它还支持自定义类型,真是有个博大的胸襟!!!

似乎Qt自己的类型全部都支持了,不过好像没有QObject。

所以,遇到类型问题,不要着急,试着往QVariant里面塞,看看是否已经支持了。

二、用QVariant保存任意类型与层次数据

我们下面测试中,使用QSetting操作ini配置文件,写入QVariant类型键值,并读取,来验证与写入内容是否一致。

QSettings* setting = new QSettings(qApp->applicationDirPath() + "/setting.ini", QSettings::IniFormat);

1. 保存QStringList

// 测试写入、读取QStringList
void test_QStringList(QSettings *setting)
{
    // 定义
    QStringList list;
    list << "zhangsan" << "lisi" << "wangxiaohua";

    // 写入
    setting->setValue("AppAttribute/QStringList", list);

    // 读取
    QStringList listResult = setting->value("AppAttribute/QStringList").toStringList();
    qDebug() << listResult;
    qDebug() << "-----------------------------------------------\n";
}

运行结果:
在这里插入图片描述

2. 保存结构体

// 测试写入、读取结构体对象
void test_StructObject(QSettings *setting)
{
    // 定义结构体
    QMap<QString, QVariant> person;
    person["name"] = "zhangsan";
    person["age"] = 25;
    person["sex"] = "man";

    // 写入
    setting->setValue("AppAttribute/Person", person);

    // 读取
    QMap<QString, QVariant> result = setting->value("AppAttribute/Person").toMap();
    qDebug() << result;
    qDebug() << "-----------------------------------------------\n";
}

运行结果:
在这里插入图片描述

3. 保存结构体嵌套

// 测试写入、读取结构体下面嵌套结构体
void test_NestedStructObject(QSettings *setting)
{
    // 定义嵌套结构体
    QMap<QString, QVariant> car;
    car["brand"] = "Audi";
    car["price"] = 20;

    QMap<QString, QVariant> person;
    person["name"] = "zhangsan";
    person["age"] = 25;
    person["sex"] = "man";
    person["car"] = car;

    // 写入
    setting->setValue("AppAttribute/PersonCar", person);

    // 读取
    QMap<QString, QVariant> result = setting->value("AppAttribute/PersonCar").toMap();
    qDebug() << result;
    qDebug() << "-----------------------------------------------\n";
}

运行结果:
在这里插入图片描述

4. 保存对象列表

// 测试写入、读取结构体对象列表
void test_StructObjectList(QSettings *setting)
{
    // 定义结构体列表
    QMap<QString, QVariant> person1;
    person1["name"] = "zhangsan";
    person1["age"] = 25;
    person1["sex"] = "man";

    QMap<QString, QVariant> person2;
    person2["name"] = "lisi";
    person2["age"] = 30;
    person2["sex"] = "woman";

    QList<QVariant> list;
    list << person1 << person2;

    // 写入
    setting->setValue("AppAttribute/Persons", list);

    // 读取
    QList<QVariant> result = setting->value("AppAttribute/Persons").toList();
    qDebug() << result;
    qDebug() << "-----------------------------------------------\n";
}

运行结果:
在这里插入图片描述

5. 保存对象树

// 测试写入、读取结构体对象树
void test_StructObjectTree(QSettings *setting)
{
    // 定义结构体对象树
    QMap<QString, QVariant> car1_0;
    car1_0["brand"] = "Audi";
    car1_0["price"] = 20;

    QMap<QString, QVariant> car1_1;
    car1_1["brand"] = "bmw";
    car1_1["price"] = 30;

    QMap<QString, QVariant> person1;
    person1["name"] = "zhangsan";
    person1["age"] = 25;
    person1["sex"] = "man";

    QList<QVariant> cars_1;
    cars_1 << car1_0 << car1_1;
    person1["cars"] = cars_1;

    /////////////////////////////////////////
    QMap<QString, QVariant> car2_0;
    car2_0["brand"] = "VOLVO";
    car2_0["price"] = 32;

    QMap<QString, QVariant> car2_1;
    car2_1["brand"] = "Benz";
    car2_1["price"] = 40;

    QMap<QString, QVariant> person2;
    person2["name"] = "lisi";
    person2["age"] = 31;
    person2["sex"] = "woman";

    QList<QVariant> cars_2;
    cars_2 << car2_0 << car2_1;
    person2["cars"] = cars_2;

    QList<QVariant> persons;
    persons << person1 << person2;

    // 写入
    setting->setValue("AppAttribute/PersonTree", persons);

    // 读取
    QList<QVariant> personsResult = setting->value("AppAttribute/PersonTree").toList();
    qDebug() << personsResult;
    qDebug() << "-----------------------------------------------\n";
}

运行结果:
在这里插入图片描述

结构越复杂,toString之后,可读性越低。

三、总结

QVariant实际上是实现了,以一种通用的类型,来有效组织任意类型,层次的数据,并实现了针对任意类型,层次数据的序列化、反序列化。

即对任意类型、层次数据可以自动转QString,对QString也可以自动转成最初的结构数据。

QVariant类似于实现了XML这样的可伸缩数据结构,而XML需要手写各种标签和组织层次。QVariant只需要你把数据按你自己的层次结构放进去就可以了,至于如何序列化,反序列化,你都不用关心。

正如,上面的测试代码,如果你觉得QVariant是一个值,那就错了,它可以是Any things。QSettings的设置键值方法:

void setValue(const QString &key, const QVariant &value);

同样道理,键值可以是一个list,也可以是一个map。所以有了QVariant,实现任意类型数据保存为配置,是多么easy的一件事情。

比如,我们有很多算法,每个算法有多个不同的属性,也就是成员变量,而算法的这些属性可以通过界面来配置,以决定每个属性的赋值,此时我们就可以将算法类名及其属性构成一个QVariant,多个算法就构成一个List,我们存储到配置文件中,然后读取出来,根据类名实例化算法,并同时将配置文件中属性初始化到算法实例中。这是不是像极了类似于spring框架中赖以生存的反射应用。通过配置文件来实例化对象和初始化属性。

一个QVariant,想到了反射,这似乎有点偏了,哈哈

代码地址:

https://gitee.com/bailiyang/cdemo/tree/master/Qt/38QSetting/QVariantSetting


===================================================

===================================================

业余时间不定期更新一些想法、思考文章,欢迎关注,共同探讨,沉淀技术!

            

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章