0

I'm currently trying to connect a QML Signal to a C++ Slot unsuccessfully.

I just had a look on several other examples but I think i didn't got it with how to get the root object of a qml document...

My problem is, it seems like the signal will be sent from the qml file, but not received in the cpp file. There are no errors when I execute this code.

//Counter.h
#ifndef COUNTER_H
#define COUNTER_H

#include <QObject>

class Counter : public QObject
{
    Q_OBJECT

private:
    int counter;

public:
    explicit Counter(QObject *parent = 0);

signals:
    void counterHasChanged(int);

public slots:
    void click();
};

#endif // COUNTER_H


//counter.cpp
#include "counter.h"
#include <QDebug>

Counter::Counter(QObject *parent) :
    QObject(parent)
{
    this->counter = 0;

    qDebug() << "Class Counter created";
}

void Counter::click() {
    this->counter++;

    qDebug() << "clickRegistered() - emit counterHasChanged()";

    emit counterHasChanged(counter);
}



//main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "counter.h"
#include <QObject>
#include <QtQuick>
#include <QDebug>
#include <QQuickItem>
#include <QQmlContext>
#include <QtCore>

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

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/StatesTest2/main.qml"));
    viewer.showExpanded();

    QQuickView view;
    view.setSource(QUrl::fromLocalFile("qml/StatesTest2/main.qml"));

    QObject *item = view.rootObject();

    Counter counter;

    QObject::connect(item, SIGNAL(click()), &counter, SLOT(click()));

    return app.exec();
}



//main.qml
import QtQuick 2.0

Rectangle {
    id: root
    width: 360
    height: 360

    signal click

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

    MouseArea {

        anchors.fill: parent
        onClicked: {
            root.click
            console.log("click() qml")
        }
    }

    Text {
        text: "clicks: "
        x: 30
        y: 250
    }

    Text {
        id: counter
        text: "0"
        x: 75
        y: 250
    }
}

I know there are tons of topics like this.. For some reason, no other solution worked for me.. maybe I should change my IDE :D

DragonHawk
  • 39
  • 7

2 Answers2

2

I suggest you to add counter as a context property.. This requires following changes.

//Counter.h
#ifndef COUNTER_H
#define COUNTER_H

#include <QObject>

class Counter : public QObject
{
    Q_OBJECT

private:
    int counter;

public:
    explicit Counter(QObject *parent = 0);

signals:
    void counterHasChanged(int Value);

public slots:
    void click();
};

#endif // COUNTER_H

The Counter.cpp file

//counter.cpp
#include "counter.h"
#include <QDebug>

Counter::Counter(QObject *parent) :
    QObject(parent)
{
    this->counter = 0;

    qDebug() << "Class Counter created";
}

void Counter::click() {
    this->counter++;

    qDebug() << "clickRegistered() - emit counterHasChanged()";

    emit counterHasChanged(counter);
}

The main.cpp file

   //main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "counter.h"
#include <QObject>
#include <QtQuick>
#include <QDebug>
#include <QQuickItem>
#include <QQmlContext>
#include <QtCore>

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

    Counter counter;
    QtQuick2ApplicationViewer viewer;
    viewer.rootContext()->setContextProperty("counterObj",&counter);

    viewer.setMainQmlFile(QStringLiteral("qml/SO_QMLCPPCommunication/main.qml"));


    viewer.showExpanded();

    return app.exec();
}

And in the qml file, you can access the slot of the Counter object by referring to counterObj.

  //main.qml
import QtQuick 2.0

Rectangle {
    id: root
    width: 360
    height: 360

    signal click

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

    MouseArea {

        anchors.fill: parent
        onClicked: {
            counterObj.click()
            console.log("click() qml")
        }
    }

Text {
    text: "clicks: "
    x: 30
    y: 250
}

Text {
    id: counter
    text: "0"
    x: 75
    y: 250
}
Connections
{
    id:cppConnection
    target:counterObj
    ignoreUnknownSignals : true
    onCounterHasChanged:{
          //To access signal parameter,please name the parameter.
          console.debug("Counter value changed")
          counter.text = Value
   }
}

}
Programmer
  • 1,290
  • 2
  • 12
  • 16
  • That worked for me very well! One more question. If I use this solution, how can I send a signal from c++ back to qml? For example: MouseArea was clicked, areaClicked() signal to c++. Then I want to increase the value of the counter and want to send a signal "counterValueChanged()" back to qml to update a textField or something else. – DragonHawk Mar 24 '14 at 11:06
  • You need to use QML [Connections](http://qt-project.org/doc/qt-5/qml-qtqml-connections.html) component for that with target being *counterObj*. Then you can handle the signal from Counter... Brief snippet Connections{target:counterObj;onCounterValueChanged:{//do your stuff here.}}. – Programmer Mar 24 '14 at 11:12
  • If I want to execute the code, I receive an error "unkown counterObj property [...]". Maybe I have to solve it in my header-file with "Q_PROPERTY(...NOTIFY...)"? (?) Another question.. If I am using the Connections class, do I still need the QObject::connect-method? The documentation [Connections](http://qt-project.org/doc/qt-5/qml-qtqml-connections.html) is in my opinion horrible for beginners. That document didn't help me ... – DragonHawk Mar 24 '14 at 13:01
  • I apologize for the delayed response. I had some issues with my internet connection. I have edited my answer and posted the entire source code. This worked fine when I tested it in my system. – Programmer Mar 25 '14 at 07:51
  • Works wonderful! One additional note: I wrote in the comments that I received an error "ReferenceError: counterObj is not defined". I just got this because in my main.qml the line `viewer.rootContext()->setContextProperty("counterObj",&counter);` was executed AFTER `viewer.setMainQmlFile(QStringLiteral("qml/ProjektName/main.qml"));` – DragonHawk Mar 25 '14 at 08:24
  • I noticed that. I changed my code after that. Sorry, I was lazy to test it for the first time :) – Programmer Mar 25 '14 at 08:26
0

QQuickView::rootObject() returns you a QQuickItem which apparently on Qt5.0 hasn't any click signal (http://qt-project.org/doc/qt-5.0/qtquick/qquickitem.html)

Make sure you're linking the right (existing) signal to the right slot and that the signal gets actually called.

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • I wanted to add my own signal to send it to the cpp file. Isn't that possible with QQuickItem? – DragonHawk Mar 24 '14 at 09:32
  • Qt should print a message to your output window/ debug console and `QObject::connect()` will return false if failed ... – Zaiborg Mar 24 '14 at 09:37
  • @Zaiborg: if ( QObject:: ... ) is true I'm just trying to test the connection with Connection::operator. Seems like this should also be true if the connection was successfully. – DragonHawk Mar 24 '14 at 09:48
  • @user3411048 if you want to add your own signal you should subclass the control (if that's intended to be subclassed, but you can easily find out by the privileges for the constructors). I 100% discourage you to change the source code if you're compiling Qt from scratch. – Marco A. Mar 24 '14 at 09:52
  • What is the difference between my code and this one: [Connecting to QML Signals](http://qt-project.org/doc/qt-5.1/qtqml/qtqml-cppintegration-interactqmlfromcpp.html#connecting-to-qml-signals) ?? – DragonHawk Mar 24 '14 at 09:56
  • I'm not familiar with QML but you have a Rectangle instead of an Item. And the type of the object you're telling has the slot it's an Item. – Marco A. Mar 24 '14 at 10:19
  • I just copied the example in the previous link into a new project and added the necessary include-statements. This example also don't work for me. It seems the QObject::connect is successful but the signal will not be transfered / received by the c++ file. – DragonHawk Mar 24 '14 at 10:27
  • First fix the types, then make sure that the signal is actually sent from that object, otherwise it's a no-go – Marco A. Mar 24 '14 at 10:29