访问存储在QVariant中的枚举

时间:2010-04-01 12:24:09

标签: qt4

我在头文件中注册了一个枚举类型“ClefType” - 这个枚举使用Q_DECLARE_METATYPE和Q_ENUMS宏在MetaObject系统中注册。 qRegisterMetaType也在类构造函数中调用。

这允许我在Q_PROPERTY中使用此类型,这一切都正常。但是,稍后,我需要能够在给定对象的情况下获得此枚举类型的Q_PROPERTY - 以适合序列化的形式。

理想情况下,存储该枚举成员的整数值会很有用,因为我不希望它特定于所使用的枚举类型 - 最终我希望有几个不同的枚举< /强>

// This is inside a loop over all the properties on a given object
QMetaProperty property = metaObject->property(propertyId);
QString propertyName = propertyMeta.name();
QVariant variantValue = propertyMeta.read(serializeObject);

// If, internally, this QVariant is of type 'ClefType',
// how do I pull out the integer value for this enum?

不幸的是variantValue.toInt();不起作用 - 自定义枚举似乎不能直接“转换”为整数值。

提前致谢,

亨利

5 个答案:

答案 0 :(得分:1)

尝试:

int x = variantValue.value<ClefType>();

答案 1 :(得分:1)

您可以使用QVariant的>><<运算符来完成此操作。

保存(MyClass *x = new MyClass(this);outQDataStream):

const QMetaObject *pObj = x->pObj();
for(int id = pObj->propertyOffset(); id < pObj->propertyCount(); ++id)
{
    QMetaProperty pMeta = pObj->property(id);
    if(pMeta.isReadable() && pMeta.isWritable() && pMeta.isValid())
    {
        QVariant variantValue = pMeta.read(x);
        out << variantValue;
    }
}

装载:

const QMetaObject *pObj = x->pObj();
for(int id = pObj->propertyOffset(); id < pObj->propertyCount(); ++id)
{
    QMetaProperty pMeta = pObj->property(id);
    if(pMeta.isReadable() && pMeta.isWritable() && pMeta.isValid())
    {
        QVariant variantValue;
        in >> variantValue;
        pMeta.write(x, variantValue);
    }
}

您需要致电

    qRegisterMetaType<CMyClass::ClefType>("ClefType");
    qRegisterMetaTypeStreamOperators<int>("ClefType");

除了使用Q_OBJECTQ_ENUMSQ_PROPERTY之外。调用qRegisterMetaTypeStreamOperators<int>告诉Qt使用operator<<operator>>的int版本。

顺便说一下:使用qRegisterMetaType<CMyClass::ClefType>()而不是名字的形式对我不起作用。如果您使用返回的id来查找名称,可能会更容易。

仅供参考,这是MyClass定义:

class CMyClass : public QObject
{
    Q_OBJECT
    Q_ENUMS(ClefType)
    Q_PROPERTY(ClefType cleftype READ getCleftype WRITE setCleftype)
public:
    CMyClass(QObject *parent) : QObject(parent), m_cleftype(One)
    {
        qRegisterMetaType<CMyClass::ClefType>("ClefType");
        qRegisterMetaTypeStreamOperators<int>("ClefType");
    }
    enum ClefType { Zero, One, Two, Three };
    void setCleftype(ClefType t) { m_cleftype = t; }
    ClefType getCleftype() const { return m_cleftype; }
private:
    ClefType m_cleftype;
};

Q_DECLARE_METATYPE(CMyClass::ClefType)

答案 2 :(得分:1)

我遇到了同样的问题,并提出了以下解决方案,适用于任何枚举类型:

int x = property.enumerator().value(*reinterpret_cast<const int *>(variantValue.constData()));

答案 3 :(得分:1)

您可以使用新的Q_ENUM宏(Qt 5.5中已添加),而不必担心调用qRegisterMetaType()。我写了一个测试应用程序(使用Google测试)向我证明它有效:

#include <gtest/gtest.h>

#pragma warning(push, 0)
#include <QObject>
#include <QtTest/QSignalSpy>
#pragma warning(pop)

class tColoredObject : public QObject
{
    Q_OBJECT

public:
    enum class eColor
    {
        Red = 1,
        Blue = 2,
        Green = 3
    };
    Q_ENUM(eColor)

    tColoredObject() : m_color(eColor::Red) {}

    void SendSignal(tColoredObject::eColor color) { emit TestSignal(color); }

signals:
    void TestSignal(tColoredObject::eColor color);

private:
    eColor m_color;
};

TEST(Enum, EnumValue)
{
    const QVariant varRed = QVariant::fromValue(tColoredObject::eColor::Red);
    const QVariant varBlue = QVariant::fromValue(tColoredObject::eColor::Blue);
    const QVariant varGreen = QVariant::fromValue(tColoredObject::eColor::Green);

    EXPECT_EQ(varRed.toUInt(), static_cast<uint>(tColoredObject::eColor::Red));
    EXPECT_EQ(varBlue.toUInt(), static_cast<uint>(tColoredObject::eColor::Blue));
    EXPECT_EQ(varGreen.toUInt(), static_cast<uint>(tColoredObject::eColor::Green));

    EXPECT_TRUE(varRed.canConvert<tColoredObject::eColor>());
    EXPECT_TRUE(varBlue.canConvert<tColoredObject::eColor>());
    EXPECT_TRUE(varGreen.canConvert<tColoredObject::eColor>());

    EXPECT_EQ(varRed.value<tColoredObject::eColor>(), tColoredObject::eColor::Red);
    EXPECT_EQ(varBlue.value<tColoredObject::eColor>(), tColoredObject::eColor::Blue);
    EXPECT_EQ(varGreen.value<tColoredObject::eColor>(), tColoredObject::eColor::Green);
}

TEST(Enum, EmitFunctionSucceeds)
{
    tColoredObject objColor;
    QSignalSpy OnTestSignal(&objColor, &tColoredObject::TestSignal);

    objColor.TestSignal(tColoredObject::eColor::Blue);
    EXPECT_EQ(1, OnTestSignal.count());
    QList<QVariant> arguments = OnTestSignal.takeFirst();
    EXPECT_EQ(tColoredObject::eColor::Blue, arguments.at(0).value<tColoredObject::eColor>());
}

答案 4 :(得分:0)

我的非花哨解决方案是对 int 进行类型转换。我不知道它是否因为新的编译器而有效(原始问题有十多年了),但是在使用 QSettings 设置值时它有效:

enum iconSep_e {
    sepNone,
    sepSpace,
    sepTab,
};

在函数内部...

QSettings settings;
settings.setValue(QStringLiteral("iconSep"), sepTab);

检索时,我直接打开 int,但使用 enum 作为大小写值:

QVariant var = settings.value(QStringLiteral("iconSep"));
if (!var.isNull()) {
    int iconSep = var.toInt();
    switch (iconSep) {
    case sepNone:
        ui->radioIconSepNone->setChecked(true);
        break;
    case sepSpace:
        ui->radioIconSepSpace->setChecked(true);
        break;
    case sepTab:
        ui->radioIconSepTab->setChecked(true);
        break;
    }
}

我做了一些测试,类型转换也有效:

enum iconSep_e iconSep = static_cast<enum iconSep_e>(var.toInt());