setProperty() 返回 false

setProperty() returning false

我正在尝试将 QVariantMap 转换为派生自 QObject 的自定义 class,但我得到 false 的 return 值从 setProperty() 开始设置我的枚举类型的 属性 。代码如下:

MessageHeader.h文件:

// deserialization class header
class MessageHeader : public QObject
{
    Q_OBJECT

public:
    MessageHeader(QObject *parent = 0);
    ~MessageHeader();

    enum class MessageType
    {
        none = 0,
        foo = 1,
        baa = 2
    };

    Q_ENUM(MessageType)
    Q_PROPERTY(MessageType type READ getType WRITE setType)
    Q_PROPERTY(int ContentLength READ getContentLength WRITE setContentLength)

    void setType(MessageType type);
    void setContentLength(int ContentLength);
    MessageType getType();
    int getContentLength();
    QString toString();

    MessageType type = MessageType::none;
    int ContentLength = 0;
};

MessageHeader.cpp文件:

MessageHeader::MessageHeader(QObject *parent)
    : QObject(parent)
{
}

MessageHeader::~MessageHeader()
{
}

MessageType MessageHeader::getType()
{
    return type;
}

int MessageHeader::getContentLength()
{
    return ContentLength;
}

void MessageHeader::setType(MessageType type)
{
    this->type = type;
}

void MessageHeader::setContentLength(int ContentLength)
{
    this->ContentLength = ContentLength;
}

QString MessageHeader::toString()
{
    return QString("NOT IMPLEMENTED YET");
}

反序列化函数模板助手:

  template<typename T>
    T* Deserialize(const QString &json)
    {
        bool status = false;

        QJson::Parser parser;
        QVariantMap map = parser.parse(json.toUtf8(), &status).toMap();

        if(!status)
            return NULL;

        T *obj = new T(); //don't worry about this, I'll rather take this from paramters once this is working
        QObject *p = (QObject *) obj; // cast done so that I see setProperty() method
        for(QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter)
        {
            const char *name = iter.key().toLatin1();
            const QVariant value = iter.value();
            qDebug() << "setting " << name << "=" << value;
            // the issue goes below. Here setProperty() return false.
            // At this point, name = 'type' and value = 2
            assert(p->setProperty(name, value));
        }
    //QJson::QObjectHelper::qvariant2qobject(map, obj);
    return obj;
}

上面函数的JSON输入字符串是这样的:

"{\"ContentLength\": 100, \"type\": 2}"

枚举类型首先在 main 函数中注册:

qRegisterMetaType<MessageType>("MessageType");

这是 QJson library used in this example. I build it on Windows with this .pro 文件

编辑:

刚刚发现 属性 类型无法被 indexOfProperty()

找到
qDebug() << "id = " << meta->indexOfProperty(name); // print -1, name = 'type'

枚举 属性 只能在变体类型为 QStringQIntQUInt 时设置,如 here. So to successfully set the enum property, the variant needs to be one of these types and nothing else. QJson parses any unsigned integers as QULongLong as can be seen here, line 84 所示。因此,一种方法是分叉 QJson 并修改代码,以便将整数值转换为 QIntQUInt 或 read/write 枚举值作为字符串。

此外,将语句放在 assert 中不是一个好主意,但我假设您只是为了找出问题而编写了该代码。

作为旁注,根据 Qt 文档,

[qRegisterMetaType] is useful only for registering an alias (typedef) for every other use case Q_DECLARE_METATYPE and qMetaTypeId() should be used instead.

所以在 header 中用 Q_DECLARE_METATYPE(MessageHeader::MessageType) 替换 qRegisterMetaType<MessageHeader::MessageType>("MessageType") 是一个合理的举动。

在 Rostislav 的回答的基础上,如果您别无选择只能接收 QULongLong 作为输入,如果要设置的 属性 是一个枚举,这里有一个代码片段来转换它:

#include <QMetaProperty>

const QMetaObject* meta = object->metaObject();
const int index = meta->indexOfProperty(propName);
if (index == -1) {/* report error*/}
if (meta->property(index).isEnumType())
    // special case for enums properties: they can be set from QInt or QUInt variants,
    // but unsigned integers parsed from json are QULongLong
    object->setProperty(propName, propVariant.value<unsigned int>());
else
    object->setProperty(propName, propVariant);