有容乃大的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


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

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

業餘時間不定期更新一些想法、思考文章,歡迎關注,共同探討,沉澱技術!

            

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