Qt之QVariant用法

本文详细介绍了Qt中的QVariant类,它可以存储各种数据类型,包括基本类型、容器类型以及自定义类型。文章通过代码示例展示了如何使用QVariant来存储不同类型的数据,并解释了其内部实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简介

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的应用:

2.代码片段

//一.基本数据类型

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。

3.源码赏析

数据成员

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

构造函数

可以存储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);

取值

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

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); }
<think>我们正在讨论Qt中的QVariant类,它是一个可以存储多种数据类型的容器,用于在Qt的各个部分之间传递数据。 用户要求一个使用示例,我们将展示如何存储不同的数据类型到QVariant中,以及如何从QVariant中取出数据。 注意:由于用户指定了Qt版本为5.12.8,我们将确保示例在该版本下有效。 步骤: 1. 包含必要的头文件:<QVariant> 2. 创建QVariant对象并存储不同类型的数据。 3. 使用相应的方法将QVariant转换回具体类型,并注意类型安全。 示例代码: 我们将展示存储整数、字符串、浮点数、列表和自定义类型(如果可能)的示例。 注意:对于自定义类型,需要在QVariant中使用,必须使用Q_DECLARE_METATYPE宏声明,并且如果要在信号槽中使用,还需要使用qRegisterMetaType()注册。但根据用户要求,我们先展示基本类型。 另外,从QVariant中取出数据时,可以使用toInt(), toString()等方法,但要注意如果存储的类型和取出的类型不一致,可能会返回默认值(如0或空字符串)或进行转换(如数字转字符串)。如果转换失败,可能会得到0或空值,或者如果使用convert方法,则返回转换是否成功。 我们还会展示如何检查QVariant中存储的数据类型,使用type()或userType()方法,然后与QMetaType::Type枚举比较。 由于用户要求示例,我们将编写一个简单的控制台程序示例(不需要GUI)。 注意:在Qt5.12.8中,QVariant的使用方式与之前版本类似,但注意一些过时的函数。 示例代码: */ #include <QCoreApplication> #include <QVariant> #include <QDebug> #include <QStringList> #include <QPoint> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 示例1:存储基本类型 QVariant v1(42); // 整数 QVariant v2("Hello, Qt!"); // 字符串 QVariant v3(3.14159); // 双精度浮点数 // 示例2:存储Qt类型 QVariant v4(QPoint(10, 20)); // QPoint // 示例3:存储列表 QStringList list; list << "Apple" << "Banana" << "Cherry"; QVariant v5(list); // 示例4:自定义类型(需要声明元类型) // 假设我们有一个自定义结构体(在全局作用域声明) struct MyStruct { int id; QString name; }; // 为了在QVariant中使用,我们需要使用Q_DECLARE_METATYPE,注意:必须在命名空间外声明 Q_DECLARE_METATYPE(MyStruct) MyStruct custom; custom.id = 1; custom.name = "Custom"; QVariant v6 = QVariant::fromValue(custom); // 输出存储的值 qDebug() << "v1:" << v1.toInt(); // 42 qDebug() << "v2:" << v2.toString(); // "Hello, Qt!" qDebug() << "v3:" << v3.toDouble(); // 3.14159 qDebug() << "v4:" << v4.toPoint(); // QPoint(10,20) qDebug() << "v5:" << v5.toStringList(); // QStringList("Apple", "Banana", "Cherry") // 对于自定义类型,我们使用value<T>来获取 MyStruct customBack = v6.value<MyStruct>(); qDebug() << "v6:" << customBack.id << customBack.name; // 1 "Custom" // 检查类型 qDebug() << "Type of v1:" << v1.type(); // 返回QMetaType::Int qDebug() << "Type of v2:" << v2.typeName(); // 返回类型名称的字符串 return a.exec(); } /* 注意:上面的代码中,自定义类型MyStruct的元类型声明必须在结构体定义之后,且在任何使用之前。在main函数之前使用Q_DECLARE_METATYPE(MyStruct)声明。 另外,如果自定义类型在头文件中定义,则需要在每个使用它的源文件中包含该头文件,并在使用前进行元类型声明。 编译运行此程序,将输出各个变量的值。 重要:在Qt5中,QMetaType::Type枚举发生了变化,但type()方法返回的是存储类型的枚举值(在QVariant中有一个枚举,但也可以使用QMetaType::Type)。在输出时,我们使用type()方法返回的是int,但可以转换为QMetaType::Type,或者使用typeName()得到类型名称的字符串。 另外,在Qt5.12中,QVariant::type()方法已经被标记为过时(deprecated),推荐使用typeId()(Qt5.5引入)或userType()。但是,在5.12中,我们仍然可以使用type(),但为了向前兼容,我们可以使用userType()来获取类型的ID(与QMetaType::Type枚举值相同),或者使用typeName()获取类型名称。 修改检查类型的部分: qDebug() << "Type of v1:" << v1.userType(); // 返回QMetaType::Int对应的整数值 qDebug() << "Type of v2:" << v2.typeName(); // 返回"QString" 因为userType()返回的是int,我们可以用QMetaType::typeName(v1.userType())来获取类型名称,但直接使用v1.typeName()更简单。 注意:对于自定义类型,typeName()返回的是"MyStruct",但要注意,如果多个自定义类型有相同的名称但在不同的命名空间,则需要使用完整名称。 以上是一个简单的QVariant使用示例。 另外,用户可能还想知道QVariantQt中的常见应用场景,比如: - 在模型/视图框架中(如QAbstractItemModel的data()函数返回QVariant) - 在属性系统中(QObject的属性使用QVariant存储) - 在信号槽中传递多种类型(需要注册自定义类型) 由于用户只要求示例,我们提供上述代码即可。 相关问题: 1. QVariant如何存储自定义类型? 2. 在Qt中,QVariant在模型/视图框架中是如何使用的? 3. 如何安全地从QVariant中取出数据以避免运行时错误? */</think>### Qt 5.12.8 中 QVariant 使用详解 `QVariant` 是 Qt 的核心类,用于封装各种通用数据类型,允许在 Qt 框架中安全地存储和传递不同类型的数据。以下是关键用法和示例: --- #### 1. **基础类型存储与转换** ```cpp #include <QVariant> #include <QDebug> // 存储整数 QVariant intVar = 42; int num = intVar.toInt(); // 转换为 int qDebug() << "Integer:" << num; // 输出: 42 // 存储字符串 QVariant strVar = "Hello Qt"; QString text = strVar.toString(); // 转换为 QString qDebug() << "String:" << text; // 输出: "Hello Qt" // 存储浮点数 QVariant doubleVar = 3.14159; double pi = doubleVar.toDouble(); // 转换为 double ``` --- #### 2. **Qt 内置类型支持** ```cpp // 存储 QColor QVariant colorVar = QColor(Qt::red); QColor color = colorVar.value<QColor>(); // 模板转换 // 存储 QPoint QVariant pointVar = QPoint(10, 20); QPoint pt = pointVar.toPoint(); // 专用转换函数 ``` --- #### 3. **自定义类型支持** 需用 `Q_DECLARE_METATYPE` 注册自定义类型: ```cpp // 定义自定义结构体 struct Person { QString name; int age; }; Q_DECLARE_METATYPE(Person) // 注册元类型 // 存储自定义类型 Person alice {"Alice", 30}; QVariant customVar = QVariant::fromValue(alice); // 取出数据 Person p = customVar.value<Person>(); qDebug() << p.name << p.age; // 输出: "Alice" 30 ``` --- #### 4. **类型检查与安全转换** ```cpp QVariant var = 100; // 检查类型 if (var.type() == QVariant::Int) { qDebug() << "Type is integer"; } // 安全转换(失败返回默认值) bool ok; double d = var.toDouble(&ok); // ok=false,因类型不匹配 ``` --- #### 5. **容器类型存储** ```cpp // 存储 QList QVariant listVar = QVariant::fromValue(QList<int>{1, 2, 3}); auto numList = listVar.value<QList<int>>(); // 存储 QMap QVariant mapVar = QVariant::fromValue(QMap<QString, int>{{"a", 1}, {"b", 2}}); auto myMap = mapVar.value<QMap<QString, int>>(); ``` --- #### 6. **实际应用场景** - **模型/视图框架**:在 `QAbstractItemModel::data()` 中返回多种类型数据[^1] - **动态属性系统**:`QObject::setProperty("key", QVariant(...))` - **信号槽跨线程通信**:配合 `qRegisterMetaType()` 传递复杂类型 > ⚠️ 注意事项: > 1. 自定义类型需在**全局命名空间**注册 > 2. 跨线程传递需额外调用 `qRegisterMetaType<T>()` > 3. 优先使用 `value<T>()` 而非 `toInt()` 等函数避免隐式转换错误 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值