【问题标题】:setProperty() returning falsesetProperty() 返回 false
【发布时间】:2015-10-10 21:47:42
【问题描述】:

我正在尝试将QVariantMap 转换为从QObject 派生的自定义类,但是在设置我的枚举类型的属性时,我从setProperty() 获得了false 的返回值。代码如下:

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 库。我用这个 .pro 文件在 Windows 上构建它

编辑:

刚刚发现indexOfProperty()找不到type属性

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

【问题讨论】:

  • False 表示它无法设置您要求的内容。

标签: c++ json qt deserialization moc


【解决方案1】:

只有当变量类型是QStringQIntQUInt 时才能设置枚举属性,如here 所示。因此,要成功设置枚举属性,变量必须是这些类型之一,仅此而已。 QJson 将任何无符号整数解析为QULongLong,如here, line 84 所示。因此,一种方法是分叉 QJson 并修改代码,以便将整数值转换为 QIntQUInt 或将枚举值读/写为字符串。

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

顺便说一句,根据 Qt 文档,

[qRegisterMetaType] 仅用于为所有其他用例注册别名 (typedef),而应使用 Q_DECLARE_METATYPE 和 qMetaTypeId()。

因此,在标题中将 qRegisterMetaType&lt;MessageHeader::MessageType&gt;("MessageType") 替换为 Q_DECLARE_METATYPE(MessageHeader::MessageType) 将是一个合理的举措。

【讨论】:

  • 不幸的是,从枚举类更改为枚举并没有解决。是的,我只是写了这段代码试图找出问题所在。
  • @Jack 啊,确实,无范围的枚举可以隐式转换为int,而不是来自int。我完全替换了我的答案。
  • 我添加了重载并移动到Q_DECLARE_METATYPE,但仍然没有工作
  • @Jack 嗯。我实际上在我的机器上测试了这种方法。您使用的是哪个编译器和 Qt 版本?我在 VS 2013 中使用 Qt 5.4 进行了测试。
  • 呵呵,我上次回答的时候已经凌晨 4 点了。实际上,即使没有过载,它也对我有用。查看我使用的源文件here 和标题here。我的输出是“1 2”。我查看了生成的moc 文件,代码是setType(*reinterpret_cast&lt; MessageType*&gt;(_v));。所以为了安全起见,我通过写enum class MessageType : int 明确指定了枚举的底层类型。但是,没有它也对我有用。你能发布你的 moc 文件显示的内容吗?
【解决方案2】:

根据 Rostislav 的回答,如果您别无选择,只能接收 QULongLong 作为输入,如果要设置的属性是枚举,这里有一个代码 sn-p 来转换它:

#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);

【讨论】:

    猜你喜欢
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 2015-08-02
    • 2012-05-17
    • 2013-10-26
    • 2013-01-06
    • 2011-01-24
    相关资源
    最近更新 更多