首页 > 解决方案 > 当 QObject 通过引用传递时,C++ 信号的参数在 QML 中显示为“未定义”

问题描述

我有一个带有连接到 QML 处理程序的信号的 C++ 对象。但是,即使我将参数传递给信号,QML 参数仍显示为undefined.

使用BalloonAir作为 custom QObjects,我将Balloon's 信号连接void popped(Air const& air, int volume, QString message);到 QML 处理程序:

气球.qml:

import QtQuick 2.12
import QtQuick.Controls 2.12

import ReproImpl 0.1 as Impl

Item {
    id: root
    width: 500
    height: 500

    property int sharpness: 50

    readonly property Impl.Balloon impl: Impl.Balloon {
        onPopped: {
            // Output: {}
            console.log(JSON.stringify(arguments));
            // TypeError: cannot read property 'type' of undefined
            console.log("Bang!", air.type, volume, message);
        }
    }

    Button {
        anchors.centerIn: parent
        text: "Click me"

        onClicked: {
            console.log("Clicked!");
            impl.prick(sharpness)
        }
    }
}

主.cpp:

#include <QGuiApplication>
#include <QObject>
#include <QQmlEngine>
#include <QQuickView>

namespace my::ns {
    // Used as a parameter of the signal
    class Air : public QObject {
        Q_OBJECT
        Q_PROPERTY(QString type READ type)

    public:
        Air(QString type, QObject* parent = nullptr)
            : QObject{parent}
            , type_{type}
        {}

        Air(QObject* parent = nullptr)
            : Air{"", parent}
        {}

        QString type() const { return type_; }

    private:
        QString type_;
    };


    class Balloon : public QObject {
        Q_OBJECT

    public:
        Balloon(int toughness, QObject* parent = nullptr)
            : QObject{parent}
            , toughness{toughness}
        {}

        Balloon(QObject* parent = nullptr)
            : Balloon{10, parent}
        {}

    Q_SIGNALS:
        void popped(Air const& air, int volume, QString message);

    public Q_SLOTS:
        void prick(int sharpness)
        {
            if (sharpness > toughness) {
                Air air{"Hello"};
                Q_EMIT popped(air, 10, "POP!");
            }
        }

    private:
        int toughness;
    };

    void registerModule()
    {
        qmlRegisterModule("ReproImpl", 0, 1);
        qmlRegisterType<Air>("ReproImpl", 0, 1, "Air");
        qmlRegisterType<Balloon>("ReproImpl", 0, 1, "Balloon");
        qmlProtectModule("ReproImpl", 0);
    }
}

int main(int argc, char** argv)
{
    QGuiApplication app(argc, argv);

    my::ns::registerModule();

    QQuickView window(QUrl("Balloon.qml"));
    window.show();

    return app.exec();
}

#include "main.moc"

我能做些什么来解决这个问题?

这发生在 Qt 5.12.0 和 5.13.0 中。

标签: c++qtqmlqtquick2qt5.12

解决方案


无论出于何种原因,QML 都不支持参考信号参数。您正在air通过const&

void popped(Air const& air, int volume, QString message);

要使其正常工作,您需要传递一个非常量指针:

void popped(Air* air, int volume, QString message);

// ...

void prick(int sharpness)
{
    if (sharpness > toughness) {
        Air air{"Hello"};
        Q_EMIT popped(&air, 10, "POP!");
    }
}

请注意,将指针传递给已分配的堆栈是安全的airQML 不拥有它的所有权:

当数据从 C++ 传输到 QML 时,数据的所有权始终属于 C++ [除非从显式 C++ 方法调用返回 QObject]。


推荐阅读