QVariant
类作为 Qt Framework 提供的一种通用类型,使使用 C++ 的 Qt 获得了一种类似 Java 的 Object 的单根效果。我们可以将需要的数据存储在QVariant
类中,然后将这个类作为参数传递给不同的函数。这非常类似于 C 语言的void *
,后者同样也是一种通用类型。QVariant
在很多场合下都是需要的,比如我们可以给QComboBox
的每一项增加一个Qt::UserRole
的隐藏数据项,从而达到一种类似 HTML 的 select 的效果:select 的 text 和 value 具有不同的数据:显示是一种效果,实际则是另外的值。
这一特性非常有用,但是,QVariant
却不能保存我们的 enum。enum 非常适合于作为这种 value 的选择值,然而QVarant
却不能接受。本文就是要解决这一问题,让QVarant
同 enum 能够协同工作起来。
下面我们来看一个简单的类:
class EnumValue { public: enum Values { V1 = 100, V2, V3 }; };
我们希望将EnumValue::Values
这个 enum 存入QVariant
,然后将其再赋值给一个EnumValue::Values
变量。
将QVariant
对象转换成某一个特定类型,也就是从QVariant
中取出原始值的时候,Qt 提供了一系列 to 函数,比如toInt()
,toDouble()
。如果没有提供这种函数,我们有QVariant::value()
函数。比如,我要将QColor
传入QVariant
,然而QVariant
并没有提供toColor()
。我们可以使用QVariant::value<QColor>();
这个函数。代码片段如下:
QColor c; QVariant var = c; // ... QColor fromVariant = var.value<QColor>();
于是,我们想使用类似的代码来处理EnumValue::Values
:
QVariant var = EnumValue::V1; EnumValue::Values ev = var.value<EnumValue::Values>(); qDebug() << "var = " << ev;
很不幸,这次出错了:
错误:'qt_metatype_id' is not a member of 'QMetaTypeId<EnumValue::Values>'
怎么回事?编译器说,没有qt_metatype_id
这个成员。原来,能够存储到QVariant
类中的数据都需要有一个qt_metatype_id
这个成员,用于在从QVariant
获取原始数据的时候能够保持存入的类型。我们的 enum 没有经过 Qt 的 moc 元对象编译器处理,也就没有这个成员。由于 enum 实际上就是 int,因此可以存入QVariant
中,但是不能使用value()
函数取出。为了解决这一问题,我们可以使用一种投机取巧的办法:
QVariant var = EnumValue::V1; EnumValue::Values ev = static_cast<EnumValue::Values>(var.toInt()); qDebug() << "var = " << ev;
没错!现在可以了。不过这种做法怎么看都有些另类。强制类型转换看起来太不专业了!怎么办呢?Qt 提供了一个宏:Q_DECLARE_METATYPE
,可以为一个类型添加 meta-data。只要加上这个,moc 就可以为我们的 enum 添加元数据了。
QVariant var = EnumValue::V1; EnumValue::Values ev = var.value<EnumValue::Values>(); qDebug() << "var = " << ev;
错误没有了,可是结果还是不正确。输出值怎么不对的?回忆一下,我们怎么能使用
QVariant var = EnumValue::V1;
将 enum 存进去了呢?既然我们没有使用Q_DECLARE_METATYPE
宏就可以将 enum 存入QVariant
,说明QVariant
已经识别出了 enum。然而后面的value()
函数却出错,说明QVariant
只是将 enum 作为 int 存了进去。既然存入时类型是 int,我们按照EnumValue::Values
取出当然没有值了!
正确的做法是:
QVariant var = QVariant::fromValue(EnumValue::V1); EnumValue::Values ev = var.value<EnumValue::Values>(); qDebug() << "var = " << ev;
这次的输出就是 100 了!这样,我们就将QVariant
与 enum 结合在一起了。记得一下几点:
- 使用
Q_DECLARE_METATYPE
声明 enum; - 使用
QVariant::fromValue()
而不是 = 创建QVariant
对象; - 使用
QVariant::value()
取出原始值。