首页 Qt 在 QVariant 中使用 enum

在 QVariant 中使用 enum

0 2.2K

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 结合在一起了。记得一下几点:

  1. 使用Q_DECLARE_METATYPE声明 enum;
  2. 使用QVariant::fromValue()而不是 = 创建QVariant对象;
  3. 使用QVariant::value()取出原始值。

发表评论

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2