How can I listen to a C++ signal from QML?

爷,独闯天下 提交于 2019-12-13 00:54:23

问题


I have what I'm calling a C++ "service" who's interface I want to expose to QML. I'm trying to use QQmlContext's setContextProperty to link the object into the QML and connect to it from a QML Connections block.

QML isn't complaining with a reference error as it did previously when I hadn't registered the service in the QML context:

qrc:/main.qml:13: ReferenceError: service is not defined

So, QML seems to find the service object now, however the QML slot javascript function is not getting invoked. I see this in Qt Creator:

Debugging starts
QML debugging is enabled. Only use this in a safe environment.
QML Debugger: Waiting for connection on port 62301...
Calling the clbk signal
Debugging has finished

There should be an In onClbk message per console.log("In onClbk"); I know that I can use QMetaObject::invokeMethod to invoke a QML object's function directly, but I am trying to have a little looser coupling through the use of signals and slots.

I would like to avoid creating a QQuickItem and instantiating the service in the QML, if at all possible.

Unfortunately, the boilerplate code is legion and this is my SSCCE.

Here is a zip file of all the project directory as created through Qt Creator 5.4.

main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    auto rc = engine.rootContext();
    auto service = new Service();
    engine.rootContext()->setContextProperty(QStringLiteral("service"), service);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    // invoke the trigger arbitrarily
    QTimer *timer = new QTimer();
    timer->setSingleShot(true);
    QObject::connect(timer, SIGNAL(timeout()), service, SLOT(trigger_clbk()));
    timer->start(4000);
    return app.exec();
}

service.h

class Service : public QQuickItem {
    Q_OBJECT

public:
    virtual ~Service(){}
signals:
    void clbk();
public slots:
    void trigger_clbk() {
        qDebug()<<"Calling the clbk signal";
        clbk();
    }
};

main.qml

import QtQuick 2.4
import QtQuick.Window 2.2

Window {
    visible: true
    MainForm {
        anchors.fill: parent
        mouseArea.onClicked: {
            Qt.quit();
        }
        // subscribe to a signal
        Connections {
            target: service
            onClbk: function(){
                console.log("In onClbk");
            }
        }
    }
}

Main.ui.qml

import QtQuick 2.3

Rectangle {
    property alias mouseArea: mouseArea

    width: 360
    height: 360

    MouseArea {
        id: mouseArea
        anchors.fill: parent
    }

    Text {
        anchors.centerIn: parent
        text: "Hello World"
    }
}

回答1:


You're trying to assign a JS function to the cblk signal handler, that's not going to work as the signal handler is the function that handles the signal. So the Connections block should read:

Connections {
    target: service
    onClbk: {
        console.log("In onClbk");
    }
}



回答2:


  1. You should explicitly use the type of service, like Service or QObject (not auto). It's good for you to ensure what you want the object do.

  2. No need define additional function in SLOT of your QML, because it self is a function. In the case if you want to use parameter, do like this:

    signals:
    void clbk(QString signalString);
    
    Connections {
    target: service
    onClbk: {
        console.log(signalString);
    }
    }
    

Notice that you must use exact name of parameters, and the type of params must be register using qRegisterMetaType.



来源:https://stackoverflow.com/questions/29995250/how-can-i-listen-to-a-c-signal-from-qml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!