0

I am emitting a signal from c++ and trying to fetch the values using Connections in qml. The codes are compiling however, due to some unknown reason qml is not able to recognise "OnSomethingHappened" and signal emitted from c++ is "somethingHappened".

I know there can be other solutions but i need to use connections in qml. This is because of architecture used in qml.

qmlclient.h

#ifndef QMLMQTTCLIENT_H
#define QMLMQTTCLIENT_H

#include <QtCore/QMap>
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttSubscription>

class QmlMqttClient;

class QmlMqttSubscription : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QMqttTopicFilter topic MEMBER m_topic NOTIFY topicChanged)
public:
    QmlMqttSubscription(QMqttSubscription *s, QmlMqttClient *c);
    ~QmlMqttSubscription();

Q_SIGNALS:
    void topicChanged(QString);
    void messageReceived(QString &msg);
    void somethingHappened(QString text);

public slots:
    void handleMessage(const QMqttMessage &qmsg);

private:
    Q_DISABLE_COPY(QmlMqttSubscription)
    QMqttSubscription *sub;
    QmlMqttClient *client;
    QMqttTopicFilter m_topic;
};

class QmlMqttClient : public QMqttClient
{
    Q_OBJECT
public:
    QmlMqttClient(QObject *parent = nullptr);

    QmlMqttSubscription *subscribe(const QString &topic);

    void sub();
private:
    Q_DISABLE_COPY(QmlMqttClient)
};


#endif // QMLMQTTCLIENT_H*/

qmlmqttclient.cpp

#include "qmlmqttclient.h"
#include <QDebug>

QmlMqttClient::QmlMqttClient(QObject *parent)
    : QMqttClient(parent)
{
}

QmlMqttSubscription* QmlMqttClient::subscribe(const QString &topic)
{
    auto sub = QMqttClient::subscribe(topic, 0);
    auto result = new QmlMqttSubscription(sub, this);
    return result;
}

QmlMqttSubscription::QmlMqttSubscription(QMqttSubscription *s, QmlMqttClient *c)
    : sub(s)
    , client(c)
{
    connect(sub, &QMqttSubscription::messageReceived, this, &QmlMqttSubscription::handleMessage);
   // m_topic = sub->topic();
}

QmlMqttSubscription::~QmlMqttSubscription()
{

}

void QmlMqttSubscription::handleMessage(const QMqttMessage &qmsg)
{
    //emit messageReceived(qmsg.payload());

    emit somethingHappened(qmsg.payload());

    qDebug() << "value -> " + qmsg.payload();
}

main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);


    QmlMqttClient *client =  new QmlMqttClient();
    client->setHostname("127.0.0.1");
    client->setPort(1883);

    client->connectToHost();
    qDebug() << client->state();

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [client]() {client->subscribe("/root/temp");});
    timer.setSingleShot(true);
    timer.start(5000);



    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("myModel",client);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        id: sensor
        color: "#ffffff"
        radius: 10
        x: 10
        y: 10

        property string address
        property string title
        property string unit

        Text{
            id: textField

            property var value : 0

            text: sensor.title + " " + value + " " + sensor.unit
            y:50
            font.family: "Helvetica"
            font.pointSize: 24
            anchors.horizontalCenter: parent.horizontalCenter
        }

        Connections
        {
            target: myModel

            onSomethingHappened: {
             console.log(" something happened " +text);
            }
        }
    }
}

On running the above codes console shows

QML debugging is enabled. Only use this in a safe environment.
1
qrc:/main.qml:33:9: QML Connections: Cannot assign to non-existent property "onSomethingHappened"
"value -> -50"
"value -> -50"
"value -> -50"
Mandeep
  • 335
  • 3
  • 13

1 Answers1

1

The signal you're trying to connect to is in QmlMqttSubscription class but your context property myModel object is of type QmlMqttClient.

QmlMqttClient *client =  new QmlMqttClient();
...
engine.rootContext()->setContextProperty("myModel",client);
Maxim Paperno
  • 4,485
  • 2
  • 18
  • 22
  • hi thank you for finding the fault. But i am wondering how can i emit the signal declared in say QmlMqttClient from handle message slot – Mandeep Nov 18 '19 at 16:03
  • @Mandeep Well, `emit` is actually just a macro which evaluates to nothing, so "emitting" a signal is essentially like invoking any other class method. So in theory you could "emit" any public method of any class. But this is typically not a good design because it breaks "encapsulation" expectancy. From your example I don't understand how `QmlMqttSubscription` even comes into play here (don't see it being used), so it is hard to advise further. – Maxim Paperno Nov 18 '19 at 16:22
  • its k i found the solution. What i did is created a slot in client and connecting it on message recieved. QmlMqttSubscription is used whenever there is a new subscription from client class. I cannot use any of them as base class because they are using each other and using one of them as base class may cause interdependencies cyclic error. – Mandeep Nov 18 '19 at 16:26
  • This is from qt examples provided for QMqtt – Mandeep Nov 18 '19 at 16:27