[Solved] C++ Signal --> using Connections --> QML Slot
-
Hello guys,
it seems that I am too stupid to understand how to connect a c++ signal to a qml slot.
(The other way seems to be more easy for me ... qml signal --> c++ slot)I just tried to build a counter. I want to click on my gui (at the moment it doesnt matter where I click) and want to count how many times I already clicked on the screen.
My first exmaple doesn't really count. It should send the value "3" to the main.qml file after the main.qml sent a signal "count()" to my count.cpp file.
Problem
If I want to run the project, I'll get the following error message:
file:// ... /main.qml:10:5: QML Connections: Cannot assign to non-existent property "onClickValueChaged"First question
If I am using the Connections component, do I need to "QObject::connect()" the (c++) signal and the (qml) slot?
The documentation ("QT5.0 QtQuick2 Connections":http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-connections.html) doesn't use it.
//I just tried in in line 17 of the cpp file, doesn't solved my problem, but maybe I used connect() in a wrong way.Second question
When do I need to set the "target:" of the Connections object?
If I understood it correctly, I can have a Button{ id: button } and use the onClick-signal of the Button somewhere else for example changing a text. Text{ id: myText text: "hello" Connections { target: button onClicked: { change the text to "blabla" }}
Is this correct?@
//counter.h
#ifndef COUNTER_H
#define COUNTER_H#include <QObject>
class Counter : public QObject
{
Q_OBJECT
public:
explicit Counter(QObject *parent = 0);signals:
void clickValueChanged(int newValue);public slots:
void count();
};#endif // COUNTER_H
@@
//counter.cpp
#include "counter.h"
#include <QDebug>
#include <QObject>
#include <QQuickView>
#include <QQuickItem>Counter::Counter(QObject *parent) :
QObject(parent)
{QQuickView view(QUrl::fromLocalFile("main.qml")); QObject *item = view.rootObject(); Counter counter; connect(item, SIGNAL(count()), &counter, SLOT(count())); //connect(&counter, SIGNAL(clickValueChanged(int)), item, SLOT(clickValueChaged(int)));
}
void Counter::count() {
qDebug() << "count()";
clickValueChanged(3);
}@@
//main.qml
import QtQuick 2.0Rectangle {
id: root
width: 360
height: 360signal count() Connections { target: area onClickValueChanged: console.log("clickValueChaged: " + newValue); } Text { text: qsTr("Hello World") anchors.centerIn: parent } MouseArea { id: area anchors.fill: parent onClicked: { console.log("count()") count() } }
}
@@
//main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/Test53/main.qml")); viewer.showExpanded(); return app.exec();
}
@Thanks in advance for your help.
I know I am a newbie :P -
you need to have an objects of your Counter in QML first, then it all works easily like described in the doc :D
Without an object how would you connect the signal to a slot? Also you don't need any connect calls in c++, because the slot will be in QML and the QML engine does the connect for you in the background.
How I would do it, register the QObject to be available in QML, in you main.cpp add (after QGuiApplication or before I don't know if that matters, but before you create the QML view obviously):
@qmlRegisterType<Counter>("Counter", 1, 0, "Counter");@that's all you have to do to make the QObject with all public slots and signals available to QML, so remove the code from your Counter constructor that is not necessary).
then you can create an object in QML simply like this:
@
import Counter 1.0
..
Counter {
// connect the signal
onClickValueChanged: console.log("clickValueChaged: " + newValue)
}
@you can use the Connections with your Counter object if you want, but as mentioned in the doc that is usually not necessary, unless you want to connect the slot somewhere else and not in the object itself.
Also you don't need a real connection from QMl to C++ slots like you did, in most cases it is easier if you give your object in QMl and id (eg "id: counter") and then call it like a function from your MouseArea of whatever:
@counter.count()@then remove the dependency in your C++ from QMl completely! otherwise it would be very hard to have more then one Counter object in QML or anywhere else without very complicated code in c++ :p
-
I didn't went through your code but here is how to work with connection from C++ to QML and vice versa.
Signal in C++ and Slot in QML
C++ :-
@class ABC : public QObject
{
Q_OBJECT
.
.
.
signals:
void countChanged(int value);};
// Somewhere in the code
ABC* abc_instance = new ABC(...)// Get the qml context from the viewer. After the following statement
// your class's instance shall be available in QML as AbcInstance
qmlContext->setContextProperty("abcInstance", abc_instance);@QML : -
@YourComponent {
.
.
.
Connections {
target: abcInstance
onCountChanged : {
console.log(value)
}}
.
.
}
@Slot in C++ and Signal in QML
C++ :-
@class ABC : public QObject
{
Q_OBJECT
.
public:
Q_INVOKABLE void setQmlItem(QQuickItem* item)
{
if(item) {
_item = item;
connect(_item,SIGNAL(itemClicked()),this,SLOT(onItemClcked()));
}
}
.
private slots:
void onItemClcked();private:
QQuickItem* _item;
};// Somewhere in the code
ABC* abc_instance = new ABC(...)// Get the qml context from the viewer. After the following statement
// your class's instance shall be available in QML as AbcInstance
qmlContext->setContextProperty("abcInstance", abc_instance);@QML : -
@YourComponent {
id : itemId
.
signal itemClicked
.
MouseArea {
onClicked{
itemClicked
}
}Componenet.onCompleted() { abcInstance.setQmlItem(itemID) }
.
.
}
@ -
- Thank you very much for these informations.
It helped me a lot!
I just successfully used Xander's code in my program.
- Thank you very much for these informations.