一、簡述
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
===================================================
===================================================
業餘時間不定期更新一些想法、思考文章,歡迎關注,共同探討,沉澱技術!