How to catch a signal emitted from cpp class in Qml ?
-
wrote on 7 Dec 2016, 12:34 last edited by
Hi all,
I am using s signal slot communication for cpp and qml interaction. but when i emit a signal from cpp class i am not able to catch that in Qml...can anyone guide me in this matter... the code is as follows...
thanks.
my .h code
#ifndef HANDLETEXTFIELD_H #define HANDLETEXTFIELD_H #include <QObject> #include <QDebug> class HandleTextField : public QObject { Q_OBJECT public: explicit HandleTextField(QObject *parent = 0); signals: void setTextField(); public slots: Q_INVOKABLE void handleSubmitTextField(); }; #endif // HANDLETEXTFIELD_H
my .cpp code
#include "handletextfield.h" HandleTextField::HandleTextField(QObject *parent) : QObject(parent) { } void HandleTextField::handleSubmitTextField() { qDebug() << "c++: HandleTextField::handleSubmitTextField:" << endl; emit setTextField(); }
my main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickWindow> #include <QQmlContext> #include "handletextfield.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<HandleTextField>("com.handletextfield",1,0,"HandleTextField"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); HandleTextField handleTextField; QObject *topLevel = engine.rootObjects().value(0); QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel); // QObject::connect(window, SIGNAL(submitTextField(QString)), // &handleTextField, SLOT(handleSubmitTextField(QString))); QObject::connect(&handleTextField, SIGNAL(setTextField()), window, SLOT(setTextField())); return app.exec(); }
my qml.main code
import QtQuick 2.3 import QtQuick.Window 2.2 import QtQuick.Controls 1.2 import com.handletextfield 1.0 Window { visible: true width: 360 height: 360 HandleTextField { id: testsignal } MouseArea { anchors.fill: parent onClicked: { testsignal.handleSubmitTextField() } } function setTextField(){ console.log("setTextField signal: catched ") } }
-
wrote on 7 Dec 2016, 12:52 last edited by
QQuick creates signal handlers for your cpp classes like:
HandleTextField { id: testsignal onSetTextField: { //your code} }
http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html#exposing-signals
-
wrote on 7 Dec 2016, 12:54 last edited by
You have 2 different objects of class HandleTextField in your code(one created in main(), the other in Qml), and you connect/send a signal from different ones. For your code to work, you have to connect the HandleTextField that you created in your Qml code, and you dont need the object in main() anymore, you don't do anything with it anyway.
In Qmal this would look like:
HandleTextField { id: testsignal onSetTextField: { console.log("signal called") } }
-
You have 2 different objects of class HandleTextField in your code(one created in main(), the other in Qml), and you connect/send a signal from different ones. For your code to work, you have to connect the HandleTextField that you created in your Qml code, and you dont need the object in main() anymore, you don't do anything with it anyway.
In Qmal this would look like:
HandleTextField { id: testsignal onSetTextField: { console.log("signal called") } }
-
You have 2 different objects of class HandleTextField in your code(one created in main(), the other in Qml), and you connect/send a signal from different ones. For your code to work, you have to connect the HandleTextField that you created in your Qml code, and you dont need the object in main() anymore, you don't do anything with it anyway.
In Qmal this would look like:
HandleTextField { id: testsignal onSetTextField: { console.log("signal called") } }
wrote on 8 Dec 2016, 09:55 last edited by@Jagh You mean to say the following part is not required in main.cpp ??
HandleTextField handleTextField; QObject *topLevel = engine.rootObjects().value(0); QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel); // QObject::connect(window, SIGNAL(submitTextField()), // &handleTextField, SLOT(handleSubmitTextField())); QObject::connect(&handleTextField, SIGNAL(setTextField()), window, SLOT(setTextField()));
only i need to emit the signal and catch it in qml..in the same way as you have done ?
-
@Jagh but if i dont create a object of handletextfield in main.cpp how can i connect the signal and slot ?
wrote on 8 Dec 2016, 13:19 last edited by- You connect objects, not classes with signal-slot mechanism. So if you connect one object HandleTextField to something, this connection will not automatically transfer to other objects of the same class.
- Exactly, that part is not required, and in fact, it doesn't do anything. Connections for one object in your C++ code don't transfer to unrelated objects in QML.
- Yep, for each signal an object emits, QML exposes a property named on<SignalName>, in your case this would be onSetTextField. You can set this property as i have done, but AFAIK it should also be possible to set it from outside, having
testsignal.onSetTextField: { console.log("signal called") }
somewhere in your Qml should suffice
-
- You connect objects, not classes with signal-slot mechanism. So if you connect one object HandleTextField to something, this connection will not automatically transfer to other objects of the same class.
- Exactly, that part is not required, and in fact, it doesn't do anything. Connections for one object in your C++ code don't transfer to unrelated objects in QML.
- Yep, for each signal an object emits, QML exposes a property named on<SignalName>, in your case this would be onSetTextField. You can set this property as i have done, but AFAIK it should also be possible to set it from outside, having
testsignal.onSetTextField: { console.log("signal called") }
somewhere in your Qml should suffice
wrote on 8 Dec 2016, 14:00 last edited by Naveen_D 12 Aug 2016, 14:01@Jagh thank you for your reply...
now i have removed that part from main.cpp...but now also when i emit a signal i am not able to catch it in Qml...
the way i am registering that handletextfiled class, is it correct ...???here is the code...
main.qml
import QtQuick 2.3 import QtQuick.Window 2.2 import QtQuick.Controls 1.2 import com.handletextfield 1.0 Window { visible: true width: 360 height: 360 HandleTextField { id: testsignal onSetTextField: { console.log("Signal catched successfully...") } } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickWindow> #include <QQmlContext> #include "handletextfield.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<HandleTextField>("com.handletextfield",1,0,"HandleTextField"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
handletextfield.cpp
#include "handletextfield.h" HandleTextField::HandleTextField(QObject *parent) : QObject(parent) { handleSubmitTextField(); } void HandleTextField::handleSubmitTextField() { qDebug() << "c++: HandleTextField::handleSubmitTextField:" << endl; emit setTextField(); qDebug()<<"Signal emitted..."<<endl; }
-
wrote on 8 Dec 2016, 14:19 last edited by
You are sending signal way too early, before there was any chance for a connection to be established. In constructor the object hasn't been fully initialized yet, in particular, the QML-interpreter hadn't had a chance to initialize the object's properties from QML side yet.
-
You are sending signal way too early, before there was any chance for a connection to be established. In constructor the object hasn't been fully initialized yet, in particular, the QML-interpreter hadn't had a chance to initialize the object's properties from QML side yet.
-
wrote on 8 Dec 2016, 14:30 last edited by
I changed your code a bit so that handleSubmitTextField() is called in more appropriate time(actually i just added a Button and called this function in onClicked handler), and the signal handler was successfully called.
To when: anytime between QML object initialization (implement Component.onCompleted if you want to catch it) and object destruction is ok.
-
I changed your code a bit so that handleSubmitTextField() is called in more appropriate time(actually i just added a Button and called this function in onClicked handler), and the signal handler was successfully called.
To when: anytime between QML object initialization (implement Component.onCompleted if you want to catch it) and object destruction is ok.
-
I changed your code a bit so that handleSubmitTextField() is called in more appropriate time(actually i just added a Button and called this function in onClicked handler), and the signal handler was successfully called.
To when: anytime between QML object initialization (implement Component.onCompleted if you want to catch it) and object destruction is ok.
-
wrote on 8 Dec 2016, 14:47 last edited by
And if you really want to execute some code as soon as possible and have a guarantee that a QML object was fully initialized by the time your code is running, do it in Component.onCompleted handler of that object.
-
wrote on 9 Dec 2016, 09:06 last edited by
Ok thanks... i will try that also...:-)
-
wrote on 13 Dec 2016, 11:42 last edited by
Hi i have doubt regarding catching a signal emitted from c++ file
if there are more than 2 .qml files does it catch the signal ?
for ex, i have one .cpp and 4 .qml such as mainform.qml,radio.qml,music.qml,setting .qml
so if i emit a signal and try to catch it in setting.qml does it work ?? -
Hi i have doubt regarding catching a signal emitted from c++ file
if there are more than 2 .qml files does it catch the signal ?
for ex, i have one .cpp and 4 .qml such as mainform.qml,radio.qml,music.qml,setting .qml
so if i emit a signal and try to catch it in setting.qml does it work ??wrote on 13 Dec 2016, 13:16 last edited by@Naveen_D
Yes it works. I have tried before. -
@Naveen_D
Yes it works. I have tried before.wrote on 13 Dec 2016, 15:44 last edited by@VincentLiu but in my case it is not working....
my code is...
this .cpp where i am emitting signal..if(!WordList.isEmpty()) { WordList.removeFirst(); WordList.removeLast(); // QMessageBox m_popupmsgbox; // m_popupmsgbox.setWindowTitle("Voice Recognizer"); // Phoneme=WordList.join(" "); // qDebug()<<"firstword"<<Phoneme<<endl; // QSpacerItem* horizontalSpacer = new QSpacerItem(500, 100, QSizePolicy::Minimum, QSizePolicy::Expanding); // m_popupmsgbox.setText( Phoneme); // QGridLayout* layout = (QGridLayout*)m_popupmsgbox.layout(); // layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount()); // m_popupmsgbox.exec(); // emitSignalFunc(); // m_emitSignal= new EmitSignalClass; // m_emitSignal->emitSignalmethod(); VoiceRecognition voice; voice.playmusicsignal(); } else { qDebug()<<"List is empty"<<endl; }
my .qml is
Rectangle{ id:voicerecRect width: settings_main_rect.width/5 height: settings_main_rect.height/4 color: "transparent" VoiceRecognition { id: voiceRecognizer onPlaymusicsignal: { console.log("Signal catched...") } } Image { id: vr_image source: "qrc:/AppbarIcon.png" //source: "qrc:/Voice-Recoder-icon.png" width: parent.width-10 height: parent.height-10 smooth: true fillMode: Image.PreserveAspectFit anchors.centerIn: parent Text { id: vrtext anchors.top: parent.bottom anchors.horizontalCenter: vr_image.horizontalCenter text: qsTr("Voice Recorder") color: "white" font.pixelSize: parent.height * (2 / 9) } MouseArea { anchors.fill: parent onClicked: { //popup.open() voicerecRect.color = 'green' voiceRecognizer.vstartVoiceRecognition() } } } } }
i have registered the class using qmlregister and i am using signal handler to catch the signal...
-
@VincentLiu but in my case it is not working....
my code is...
this .cpp where i am emitting signal..if(!WordList.isEmpty()) { WordList.removeFirst(); WordList.removeLast(); // QMessageBox m_popupmsgbox; // m_popupmsgbox.setWindowTitle("Voice Recognizer"); // Phoneme=WordList.join(" "); // qDebug()<<"firstword"<<Phoneme<<endl; // QSpacerItem* horizontalSpacer = new QSpacerItem(500, 100, QSizePolicy::Minimum, QSizePolicy::Expanding); // m_popupmsgbox.setText( Phoneme); // QGridLayout* layout = (QGridLayout*)m_popupmsgbox.layout(); // layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount()); // m_popupmsgbox.exec(); // emitSignalFunc(); // m_emitSignal= new EmitSignalClass; // m_emitSignal->emitSignalmethod(); VoiceRecognition voice; voice.playmusicsignal(); } else { qDebug()<<"List is empty"<<endl; }
my .qml is
Rectangle{ id:voicerecRect width: settings_main_rect.width/5 height: settings_main_rect.height/4 color: "transparent" VoiceRecognition { id: voiceRecognizer onPlaymusicsignal: { console.log("Signal catched...") } } Image { id: vr_image source: "qrc:/AppbarIcon.png" //source: "qrc:/Voice-Recoder-icon.png" width: parent.width-10 height: parent.height-10 smooth: true fillMode: Image.PreserveAspectFit anchors.centerIn: parent Text { id: vrtext anchors.top: parent.bottom anchors.horizontalCenter: vr_image.horizontalCenter text: qsTr("Voice Recorder") color: "white" font.pixelSize: parent.height * (2 / 9) } MouseArea { anchors.fill: parent onClicked: { //popup.open() voicerecRect.color = 'green' voiceRecognizer.vstartVoiceRecognition() } } } } }
i have registered the class using qmlregister and i am using signal handler to catch the signal...
wrote on 13 Dec 2016, 16:01 last edited by@Naveen_D
Hi, first of all, I should say that I use different ways to do this. However, according to some similar experience on it. I guess you shouldn't use a new VoiceRecognition object in your .cpp file. I don't think distinct object derived from the same class can communicate this way. Please correct me if I am wrong. Thanks -
@Naveen_D
Hi, first of all, I should say that I use different ways to do this. However, according to some similar experience on it. I guess you shouldn't use a new VoiceRecognition object in your .cpp file. I don't think distinct object derived from the same class can communicate this way. Please correct me if I am wrong. Thankswrote on 14 Dec 2016, 06:46 last edited by@VincentLiu the function in which i am emitting a signal is a global function so i need to create an obj of that class and emit.
-
@Naveen_D
Hi, first of all, I should say that I use different ways to do this. However, according to some similar experience on it. I guess you shouldn't use a new VoiceRecognition object in your .cpp file. I don't think distinct object derived from the same class can communicate this way. Please correct me if I am wrong. Thankswrote on 14 Dec 2016, 06:47 last edited by@VincentLiu what are the different ways...?
9/21