Доступ к перечислению, хранящемуся в QVariant - PullRequest
5 голосов
/ 01 апреля 2010

Я зарегистрировал тип перечисления "ClefType" в моем заголовочном файле - это перечисление зарегистрировано в системе MetaObject с использованием макросов Q_DECLARE_METATYPE и Q_ENUMS. 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(); не работает - пользовательские перечисления, кажется, не могут быть напрямую "преобразованы" в целочисленное значение.

Заранее спасибо,

Henry

Ответы [ 4 ]

1 голос
/ 19 октября 2018

Вы можете использовать новый макрос Q_ENUM (добавлен в Qt 5.5) и не беспокоиться о вызове qRegisterMetaType(). Я написал тестовое приложение (используя Google Test), чтобы доказать себе, что оно работает:

#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>());
}
1 голос
/ 07 апреля 2010

Для этого вы можете использовать операторы >> и << в QVariant.

Сохранение (где MyClass *x = new MyClass(this); и out - это QDataStream):

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_OBJECT, Q_ENUMS и Q_PROPERTY. Вызов qRegisterMetaTypeStreamOperators<int> говорит Qt использовать int версии operator<< и operator>>.

Кстати: использование qRegisterMetaType<CMyClass::ClefType>() вместо формы, которая принимает имя, не работает для меня. Возможно, если вы использовали возвращенный идентификатор для поиска имени, но это намного проще.

К вашему сведению, вот определение 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)
1 голос
/ 01 декабря 2010

У меня была такая же проблема, и я нашел решение ниже, которое работает для любого перечислимого типа:

int x = property.enumerator().value(*reinterpret_cast<const int *>(variantValue.constData()));
1 голос
/ 01 апреля 2010

Попробуйте:

int x = variantValue.value<ClefType>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...