一、简介

QVariant可以存储各种数据类型,QVariant行为类似于C/C++的union, 但在Qt中比union强大很多, QVariant内置支持所有QMetaType::Type里声明的类型如:int,QString,QFont,QColor等,甚至QList,QMap<QString, QVariant>等组成的任意复杂类型。简单的说QVariant可以存储任意数据类型,表现的类似弱语言,如JS中的var如,包括容器类型的值,如QStringlist。Qt的很多功能都是建立在QVariant类的基础之上的,如Qt对象属性及数据库功能等,在代码片段中主要分两种情况讨论QVariant的应用:

二、代码片段

//一.基本数据类型

QVariant number(27); //定义一个名为number的QVariant变量,并初始值为27,那么在这里相当于int型
    qDebug()<<number;//打印结果:QVariant(int, 27)
    qDebug()<<number;

 QStringList strList;
    strList.append("who");
    strList.append("are");
    strList.append("you");

    QMap<QString,QVariant> myMap;
    myMap.insert("one",45); //int
    myMap.insert("two","hello"); //qstring
    myMap.insert("three",QColor(0,0,0)); //qcolor
    myMap.insert("four",strList); //QStringList 类型,就是所谓的容器类型值
    //    myMap.insert("five",map); //尝试了一下,结果这里无法转化,可能是不支持这种数据类型吧,map为QMap类型
    QMapIterator<QString,QVariant> x(myMap);
    for(;x.hasNext();)
    {
        qDebug()<<x.key()<<x.next().value();
#if 0
        if(x.next().value().type() == QVariant::StringList) //判断QVariant类型,这里是判断是否为QStringList,更多的可以找手册查询一下
        {
            //           qDebug()<<x.key();
            QString str=QString("%1").arg(x.key()); //找到数据类型为QStringList的值对应的键,再通过键找到值,这里不能直接用x.next().value(),因为next会跳到下一个键值对
            qDebug()<<str;
            QStringList myList=myMap[str].toStringList(); //必要的转化
            for(int m=0;m<myList.size();m++) //遍历QStringList
            {
                qDebug()<<myList[m];
            }
        }
#endif
        //        qDebug()<<x.next().value().type();
    }

//二.自定义数据类型
因为自定义数据类型是系统中不存在的,即使创建,也需要注册一下,方便编译器识别

struct myStruct //自定义的数据类型
{
    int age;
    char name[10];
};
Q_DECLARE_METATYPE(myStruct)  //注册,必不可少

//上面这部分代码一般在头文件中完成

//    myStruct stu=  //结构体初始化
//    {
//        100,
//        "wangLei"
//    };
    myStruct stu;
    stu.age = 100;//也可以先定义变量后这样赋值
    strcpy(stu.name,"Hello./n");

    QVariant v;
    v.setValue(stu); //设置QVariant的值
    qDebug()<<"v:"<<v;

    myStruct s; //这部分代码主要是将QVariant类再转化为myStruct类,其他QVariant类转化成其他类也可用这种方法
    s=v.value<myStruct>();
    qDebug()<<"s:"<<s.age<<s.name;

如果要使自定义类型或其他非QMetaType内置类型在QVariant中使用,必须使用该宏Q_DECLARE_METATYPE
如果非QMetaType内置类型要在信号与槽中使用,必须使用qRegisterMetaType

三、源码赏析

1.数据成员

QVariant的数据成员很简单,只有一句:

  Private d;

Private 定义:

struct Private
{
    union Data
    {
        char c;
        uchar uc;
        short s;
        signed char sc;
        ushort us;
        int i;
        uint u;
        long l;
        ulong ul;
        bool b;
        double d;
        float f;
        qreal real;
        qlonglong ll;
        qulonglong ull;
        QObject *o;
        void *ptr;
        PrivateShared *shared;
    } data;
    uint type : 30;
    uint is_shared : 1;
    uint is_null : 1;
};

Private是一个结构体,核心数据成员是data,是一个union数据类型,可以存储各种整型,浮点型,QObject类指针,任意指针,共享数据指针。type指示了data中存储的数据类型,is_shared代表数据是否是共享的,is_null代表data是否为空。

那么看看type可以指示的类型有哪些:

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,
    ModelIndex = QMetaType::QModelIndex,
    PersistentModelIndex = QMetaType::QPersistentModelIndex,
    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
};

不仅包含了基本数据类型Bool、Int、Double等,还包含了core中的数据类型QChar、QPoint、QSize、QRect、QDateTime、QString,容器类型QMap、QList、QHash,gui中的数据类型QColor、QFont、QPalette、QImage、QVector、QMatrix等,还可以添加自定义类型QMetaType::User

2. 构造函数

可以存储Type中的数据类型,构造函数重载自然很多,随便列举些:

QVariant(bool b);
QVariant(double d);
QVariant(const QString &string);
QVariant(const QList<QVariant> &list);
QVariant(const QMap<QString,QVariant> &map);
QVariant(const QHash<QString,QVariant> &hash);
QVariant(const QVariant &other);

也可以通过setValue赋值

template<typename T>
inline void setValue(const T &value);

3. 取值

在已知存储类型的情况下,可以直接使用如下函数:

int toInt(bool *ok = Q_NULLPTR) const;
    uint toUInt(bool *ok = Q_NULLPTR) const;
    qlonglong toLongLong(bool *ok = Q_NULLPTR) const;
    qulonglong toULongLong(bool *ok = Q_NULLPTR) const;
    bool toBool() const;
    double toDouble(bool *ok = Q_NULLPTR) const;
    float toFloat(bool *ok = Q_NULLPTR) const;
    qreal toReal(bool *ok = Q_NULLPTR) const;
    QByteArray toByteArray() const;
    QBitArray toBitArray() const;
    QString toString() const;
    QStringList toStringList() const;
    QChar toChar() const;
    QDate toDate() const;
    QTime toTime() const;
    QDateTime toDateTime() const;
    QList<QVariant> toList() const;
    QMap<QString, QVariant> toMap() const;
    QHash<QString, QVariant> toHash() const;

#ifndef QT_NO_GEOM_VARIANT
    QPoint toPoint() const;
    QPointF toPointF() const;
    QRect toRect() const;
    QSize toSize() const;
    QSizeF toSizeF() const;
    QLine toLine() const;
    QLineF toLineF() const;
    QRectF toRectF() const;
#endif
    QLocale toLocale() const;
#ifndef QT_NO_REGEXP
    QRegExp toRegExp() const;
#endif // QT_NO_REGEXP
#ifndef QT_BOOTSTRAPPED
#ifndef QT_NO_REGULAREXPRESSION
    QRegularExpression toRegularExpression() const;
#endif // QT_NO_REGULAREXPRESSION
    QUrl toUrl() const;
    QEasingCurve toEasingCurve() const;
    QUuid toUuid() const;
    QModelIndex toModelIndex() const;
    QPersistentModelIndex toPersistentModelIndex() const;
    QJsonValue toJsonValue() const;
    QJsonObject toJsonObject() const;
    QJsonArray toJsonArray() const;
    QJsonDocument toJsonDocument() const;
#endif // QT_BOOTSTRAPPED

未知情况下,可以先使用canConvert进行查询是否可以转化,然后调用对应toXXX。

bool canConvert(int targetTypeId) const;
template<typename T>
bool canConvert() const;

自定义数据类型可使用value取值

template<typename T>
inline T value() const
{ return qvariant_cast<T>(*this); }
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐