'C++ signal to QML slot in Qt
I want to send a Signal from C++ to a Slot in my QML File.
I already got it working without and primitive type parameters, although if I want to send a QString to my QML Slot I get an error whilst connecting.
I connect in main.cpp
QObject *contentView = rootObject->findChild<QObject*>(QString("contentView"));
QObject::connect(&myObj, SIGNAL(finishedGatheringDataForItem(QString)),
contentView, SLOT(updateViewWithItem(QString)));
the relavant part of my qml File
Rectangle {
objectName: "contentView"
function updateViewWithItem(string) { console.log('got some Items'); } // slot
}
Error:
Object::connect: No such slot QDeclarativeRectangle_QML_2::updateViewWithItem(QString)
Solution 1:[1]
You should use Connections in this case (maybe it's the only way to connect).
Put your object myObj to QML file by
setContextPropertyqmlVectorForm->rootContext()->setContextProperty("YourObject", myOb);Your signal is
finishedGatheringDataForItem(QString signalString)In QML file, add Connectios likes below:
Connections { target: YourObject onFinishedGatheringDataForItem: { qmlString = signalString } }
Solution 2:[2]
Solution without Connections and any context is by connecting not signal-slot, but signal-signal. Found here.
Example code is as follows.
qml:
Window{
signal qmlSend(string textOut)
signal qmlReceive(string textIn)
onQmlReceive:{
console.log(textIn)
}
}
Header file of Background class contains
public signals:
void cppSend(QString textOut);
public slots:
void cppReceive(QString textIn);
And main.cpp connects them in this way:
1.From qml to cpp:
QObject::connect(qmlRootObject, SIGNAL(qmlSend(QString)),
backgroundObject, SLOT(cppReceive(QString)));
2.From cpp to qml:
QObject::connect(backgroundObject, SIGNAL(cppSend(QString)),
qmlRootObject, SIGNAL(qmlReceive(QString)));
Solution 3:[3]
I have tried a lot of solutions to succeed in just update QML from a C++ signal but many did not work. This solution works and has been tested, it is based on this answer: https://stackoverflow.com/a/59502860/2486332 (by @Adriano Campos)
You can send data from C++ to qml using signals, like this:
main.cpp:
#include <QQmlContext>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
// Class init
YourClass yourObject;
// Embedding C++ Objects into QML with Context Properties
QQmlContext* ctx = engine.rootContext();
ctx->setContextProperty("yourObject", &yourObject);
return app.exec();
}
main.qml:
import QtQuick 2.6
Window {
id: mainWindow
Connections {
target: yourObject
onSignalData: {
console.log("Data: " + signal_param)
textToChange.text = "Changed to: " + signal_param
}
}
Text {
id: textToChange
text: "beforeChange"
}
}
yourClass.h:
class YourClass : public QObject
{
Q_OBJECT
signals:
// Signal from YourClass
void signalData(QString signal_param);
}
yourClass.cpp:
emit signalData("Hello QML"); // Signal from yourClass
A complete tutorial about "How to Expose a Qt C++ Class with Signals and Slots to QML" is available on this page: https://felgo.com/cross-platform-development/how-to-expose-a-qt-cpp-class-with-signals-and-slots-to-qml
Solution 4:[4]
For those who also stumbled upon this question, I want to say that Everything is much simpler. You just need the signal from C++ to have QVariant arguments. For example:
QObject::connect(&recipient, SIGNAL(resTalk(QVariant)), engine.rootObjects().at(0)->findChild<QObject*>("winSettings"),
SLOT(showWithErrorNetwork(QVariant)));
My signal is declared like this:
signals:
void resTalk(QVariant res);
So I'm calling the signal:
emit resTalk(true); //For more complex types, use 'emit yourSignal(QVariant(yourArg))'
And here is the slot I have in QML:
function showWithErrorNetwork(isNoError=false) {
if(!isNoError) {
visible = true
warningText.text = "Network error. Check the data."
warningText.visible = true
}
}
Solution 5:[5]
Why not use rootContext?
in c++ side you have:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
//--------------------------------------------------------
#include <myClass.h>
//--------------------------------------------------------
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
//--------------------------------------------------------
myClass * myobj = new myClass(&app);
//--------------------------------------------------------
//--------------------------------------------------------
engine.rootContext()->setContextProperty("myobj",myobj);
//--------------------------------------------------------
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
and in qml side you have:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
//--------------------------------------------------------
Component.onCompleted: {
myobj.onSomeSignal.connect(signalHandling)
}
//--------------------------------------------------------
//--------------------------------------------------------
function signalHandling(){
console.log("Signal emitted from c++ side")
}
//--------------------------------------------------------
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | zwcloud |
| Solution 2 | |
| Solution 3 | quent |
| Solution 4 | ?????? ???????? |
| Solution 5 | Reza Soleimani |
