将Q_GADGET作为信号参数从C ++传递到QML

将Q_GADGET作为信号参数从C ++传递到QML

问题描述:

无法在QML代码中获取C ++对象的属性. 对象作为参数传递给信号.

Can't get a property of a C++ object inside a QML code. Object is passed as a parameter to the signal.

预期在QML中,可以提取Record对象的属性text.并且该值应为abc. QML将对象视为QVariant(Record),并将其属性text视为undefined.

Expected that in QML, the property text of the Record object can be extracted. And the value should be abc. QML sees the object as QVariant(Record), and its property text as undefined.

Record是类似于QPoint的值类型,因此它使用Q_GADGET声明.

Record is a value-type like QPoint, so it uses Q_GADGET declaration.

hpp:

#ifndef LISTENP_HPP_
#define LISTENP_HPP_

#include <QObject>

#include "Record.hpp"

class ListenP: public QObject
{
Q_OBJECT

public:
    ListenP();
    virtual ~ListenP();

    void emitGotRecord();

signals:
    void gotRecord(Record r);
};

#endif /* LISTENP_HPP_ */

cpp:

#include "ListenP.hpp"

ListenP::ListenP() :
        QObject()
{
}

ListenP::~ListenP()
{
}

void ListenP::emitGotRecord()
{
    emit gotRecord(Record("abc"));
}

记录的hpp:

#ifndef RECORD_HPP_
#define RECORD_HPP_

#include <QObject>
#include <QMetaType>

class Record
{
Q_GADGET

Q_PROPERTY(QString text READ text WRITE setText)

public:
    Record(const QString& text = "");
    ~Record();

    QString text() const
    {
        return m_text;
    }

    void setText(const QString& text)
    {
        m_text = text;
    }

private:
    QString m_text;
};

Q_DECLARE_METATYPE(Record)

#endif /* RECORD_HPP_ */

记录的cpp:

#include "Record.hpp"

Record::Record(const QString& text) :
        m_text(text)
{
}

Record::~Record()
{
}

namespace
{
const int RecordMetaTypeId = qMetaTypeId<Record>();
}

QML片段:

Connections {
    target: listenPModel
    onGotRecord: {
        console.log(r)
        console.log(r.text)
    }
}

主要作品:

QGuiApplication app(argc, argv);

auto listenP = std::make_shared<ListenP>();
QQuickView view;
view.rootContext()->setContextProperty("listenPModel", &*listenP);
view.setSource(QStringLiteral("src/qml/main.qml"));
view.show();

QtConcurrent::run([=]
{
    QThread::sleep(3);
    listenP->emitGotRecord();
});

return app.exec();

日志显示:

qml: QVariant(Record)
qml: undefined

发行说明 Qt 5.5表示新功能:

The release notes for Qt 5.5 says for the new features:

  • Qt核心
    • 您可以现在在Q_GADGET中包含Q_PROPERTY和Q_INVOKABLE ,并且有一种方法可以使用QMetaType系统查询此类小工具的QMetaObject
  • Qt Core
    • You can now have Q_PROPERTY and Q_INVOKABLE within a Q_GADGET, and there is a way to query the QMetaObject of such gadget using the QMetaType system

实际上,使用Qt 5.4编译并运行您的示例所得到的结果与您使用使用Qt 5.5所得到的结果相同,即我正确识别了Record,即我得到了一个结果:

Indeed, compiling and running your example with Qt 5.4 gives the same result as yours whereas with Qt 5.5 I got Record correctly recognised, i.e. I got as a result:

qml: Record(abc)
qml: abc

此外,如Q_DECLARE_METATYPE 文档所述,类型传递给宏-在这种情况下,Record应该提供(1)公共默认构造函数,(2)公共副本构造函数和(3)公共析构函数.由于Record是一个非常简单的类,因此无需提供副本构造函数,因为默认构造函数就足够了.

Also, as stated in the Q_DECLARE_METATYPE documentation, the type passed to the macro - Record in this case, should provide (1) a public default constructor, (2) a public copy constructor and (3) a public destructor. Since Record is a very simple class, there's no need to provide a copy constructor as the default one is sufficient.