How to Invoking QML Methods with c++ and connect(..,signal,...,slot) ?
-
i want to invoke qml function with c++ and use the signal and slot(QObject::connect).
i don't want to invokemethod(https://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html).
don't use : qqmlengine / QMetaObject::invokeMethod
only, i use qquickview/connect ...
please help me.Here is the code that I wrote. I think that this is normal working.... why don't work...?
this code works : qml->cpp.
This code does not work : cpp->qmltouch next -> controlEvent in QmltoCppControl.cpp -> case 10: -> nextScreen -> emit SendMsgtoQml_ChangeScreen((QVariant)varData); in QmltoCppControl::nextScreen
-> and function onChangeScreenQml(msg) in main.qml
but, doesn't work function onChangeScreenQml(msg) in main.qmlwhat is problem... ??
connect or ... ???main.cpp
#include <QGuiApplication> //#include <QQmlApplicationEngine> //#include <QApplication> #include <QQuickView> #include <QtQml> #include <QObject> #include "QmltoCppControl.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; QmltoCppControl qmltocppcontrol; qmlRegisterType<QmltoCppControl>("QmltoCppControl", 1, 0, "QmltoCppControl"); view.setSource(QUrl("qrc:/main.qml")); QObject *qmlRootObject = (QObject*)view.rootObject(); QObject::connect(&qmltocppcontrol,SIGNAL(SendMsgtoQml_ChangeScreen(QVariant)), qmlRootObject,SLOT(onChangeScreenQml(QVariant)),Qt::QueuedConnection); //view.rootContext()->setContextProperty("QmltoCppControl", &qmltocppcontrol); view.show(); return app.exec(); }
QmltoCppControl.h
#ifndef QMLTOCPPCONTROL_H #define QMLTOCPPCONTROL_H #include <QObject> #include <iostream> #include <QVariant> class QmltoCppControl: public QObject { Q_OBJECT public: explicit QmltoCppControl(QObject *parent = 0); public: Q_INVOKABLE void controlEvent(int id); signals: void SendMsgtoQml_ChangeScreen(QVariant varData); private: void exitApp(); void nextScreen(); }; #endif // QMLTOCPPCONTROL_H
QmltoCppControl.cpp
#include "qmltocppcontrol.h" #include "controleventid.h" QmltoCppControl::QmltoCppControl(QObject *parent) :QObject(parent) { } void QmltoCppControl::controlEvent(int id) { std::cout << "void QmltoCppControl::controlEvent id :: "<< id << std::endl; switch(id){ case 0: { exitApp(); break; } case 10: { testnum++; nextScreen(); break; } default: { } } } void QmltoCppControl::nextScreen() { std::cout << "void QmltoCppControl::nextScreen() :: "<< std::endl; QVariantList varData; varData.clear(); varData << 1; emit SendMsgtoQml_ChangeScreen((QVariant)varData); }
main.qml
import QtQuick 2.9 import QmltoCppControl 1.0 Rectangle { id: main_rect_id x: 0 y: 0 width: 1920 height: 560 visible: true property int nScreenId: 0 function onChangeScreenQml(msg) { console.log("onChangeScreenQml\n"); qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT } QmltoCppControl { id: qmltocpp_id } Text { id: textid; font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("Hello World") anchors.centerIn: parent } Item { id: next_item_id x: main_rect_id.width/4 y: 460 width: main_rect_id.width/4 height: 100 Text { id: next_text_id font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("NEXT") anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { qmltocpp_id.controlEvent(10); //10 = EVENT_SCREEN_NEXT } } } Item { id: exit_item_id x: main_rect_id.width/4*3 y: 460 width: main_rect_id.width/4 height: 100 Text { id: exit_text_id font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("EXIT") anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT } } } }
-
Hi @LeeK , i dont think thats the right way to do it, can you explain me what functionality are you trying to achieve,so that i can help you with an optimal solution.
And by the way did you have a look into the documentation for Q_PROPERTY?
-
hi @LeeK said in How to Invoking QML Methods with c++ and connect(..,signal,...,slot) ?:
I think your issue is this:
void QmltoCppControl::nextScreen()
{
std::cout << "void QmltoCppControl::nextScreen() :: "<< std::endl;
QVariantList varData;
varData.clear();
varData << 1;
emit SendMsgtoQml_ChangeScreen((QVariant)varData);
}You simply cast (c-style cast) a QvariantList to Qvariant. That can't be a valid QVariant
-
@Shrinidhi-Upadhyaya
Thank you.
but I already know Q_Property, it isn't what I want.
@J.Hilk
Thank you.
I think it isn't the cast problem.
But I could be wrong, so I tried what you said.
It still doesn't work.
And if it's a problem, the below code should work.
But that doesn't work either.main.cpp
QObject::connect(&qmltocppcontrol,SIGNAL(SendMsgtoQml_ChangeScreen()), qmlRootObject,SLOT(onChangeScreenQml()),Qt::QueuedConnection);
QmltoCppControl.h
void SendMsgtoQml_ChangeScreen();
QmltoCppControl.cpp
emit SendMsgtoQml_ChangeScreen();
qml
function onChangeScreenQml() { console.log("onChangeScreenQml\n"); qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT }
-
Hi @LeeK , you can do one thing, you can connect the "SendMsgtoQml_ChangeScreen()" signal to a slot and in that slot you can call your QML function which is in your case "onChangeScreenQml"
For example:-
//This is just dummy connect statement
timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(dummySlot())); timer->start(10000);
//This is the slot where you can access your QML Function and object is the one which is pointing to your main.qml which in your case is "qmlRootObject" and "qmlHelloWorld" is a function in main.qml
void DummyClass::dummySlot() { qDebug() << "Another Slot"; QMetaObject::invokeMethod(object, "qmlHelloWorld"); }
You cant directly access any qml function like you have done in you main.cpp,you need to use QMetaObject::invokeMethod(). I dont know whether you can directly connect the signal to the QMetaObject::invokeMethod()!
-
@LeeK I think there a almost more easier way to do what you want!
in main.cpp
... int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; QmltoCppControl qmltocppcontrol; qmlRegisterType<QmltoCppControl>("QmltoCppControl", 1, 0, "QmltoCppControl"); view.setSource(QUrl("qrc:/main.qml")); QObject *qmlRootObject = (QObject*)view.rootObject(); view.rootContext()->setContextProperty("QmltoCppControl", &qmltocppcontrol); view.show(); return app.exec(); }
For easier code comprension; in QmltoCppControl rename signal void SendMsgtoQml_ChangeScreen(QVariant varData) to void changeScreenRequest(QVariant varData)
main.qml
import QtQuick 2.9 import QmltoCppControl 1.0 Rectangle { id: main_rect_id x: 0 y: 0 width: 1920 height: 560 visible: true property int nScreenId: 0 Connections { target: qmltocppcontrol onChangeScreenRequest: { console.log("onChangeScreenQml:" + varData); qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT } } QmltoCppControl { id: qmltocpp_id } Text { id: textid; font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("Hello World") anchors.centerIn: parent } Item { id: next_item_id x: main_rect_id.width/4 y: 460 width: main_rect_id.width/4 height: 100 Text { id: next_text_id font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("NEXT") anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { qmltocpp_id.controlEvent(10); //10 = EVENT_SCREEN_NEXT } } } Item { id: exit_item_id x: main_rect_id.width/4*3 y: 460 width: main_rect_id.width/4 height: 100 Text { id: exit_text_id font.pixelSize: 30 horizontalAlignment: Text.AlignHCenter text: qsTr("EXIT") anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT } } } }```
-
@Shrinidhi-Upadhyaya
Thank you.
but, doesn't work .. T.T
I tried the way you taught me.
If "invokeMethod" is called directly from main as below, it works normally.main.cpp
#include <QGuiApplication> #include <QQuickView> #include <QObject> #include <QtQml> #include <QQmlContext> #include "QmltoCppControl.h" int main(int argc, char *argv[]) { #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); QQuickView view; QmltoCppControl qmltocppcontrol; qmlRegisterType<QmltoCppControl>("QmltoCppControl", 1, 0, "QmltoCppControl"); view.setSource(QUrl("qrc:/main.qml")); QObject *qmlRootObject = (QObject*)view.rootObject(); view.rootContext()->setContextProperty("QmltoCppControl", &qmltocppcontrol); view.show(); QVariant returnedValue; QVariant msg = "Hello from C++"; QMetaObject::invokeMethod(qmlRootObject, "onChangeScreenQml", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, msg)); return app.exec(); }
However, it still doesn't work with signal and slot.
maybe, this is the QObject problem, but I don't know well... how to use it.
Could you help me?QObject *qmlRootObject = (QObject*)m_obj->rootObject(); QMetaObject::invokeMethod(qmlRootObject, "onChangeScreenQml", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, msg));
this is the problem code... the way you taught me.
main.cpp#include <QGuiApplication> #include <QQuickView> #include <QObject> #include <QtQml> #include <QQmlContext> #include "QmltoCppControl.h" int main(int argc, char *argv[]) { #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); QQuickView view; QmltoCppControl qmltocppcontrol; qmlRegisterType<QmltoCppControl>("QmltoCppControl", 1, 0, "QmltoCppControl"); view.setSource(QUrl("qrc:/main.qml")); QObject *qmlRootObject = (QObject*)view.rootObject(); view.rootContext()->setContextProperty("QmltoCppControl", &qmltocppcontrol); view.show(); qmltocppcontrol.m_obj = &view; return app.exec(); }
QmltoCppControl.h
#ifndef QMLTOCPPCONTROL_H #define QMLTOCPPCONTROL_H #include <QObject> #include <iostream> #include <QVariant> #include <QQuickView> #include <QDebug> //#define QARG(object,returnedValue, msg) QMetaObject::invokeMethod(object, "myQmlFunction", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, msg)) class QmltoCppControl: public QObject { Q_OBJECT public: explicit QmltoCppControl(QObject *parent = 0); void init(); QQuickView *m_obj; public: Q_INVOKABLE void controlEvent(int id); signals: void SendMsgtoQml_ChangeScreen(); public slots: void Slot_ChangeScreen(); private: void exitApp(); void nextScreen(); int testnum; }; #endif // QMLTOCPPCONTROL_H
QmltoCppControl.cpp
... QmltoCppControl::QmltoCppControl(QObject *parent) :QObject(parent) { connect(this, SIGNAL(SendMsgtoQml_ChangeScreen()), this, SLOT(Slot_ChangeScreen())); } ... void QmltoCppControl::nextScreen() { std::cout << "void QmltoCppControl::nextScreen() :: "<< std::endl; emit SendMsgtoQml_ChangeScreen(); } void QmltoCppControl::Slot_ChangeScreen() { qDebug() << "Slot_ChangeScreen()" ; QVariant returnedValue; QVariant msg = "Hello from C++"; QObject *qmlRootObject = (QObject*)m_obj->rootObject(); QMetaObject::invokeMethod(qmlRootObject, "onChangeScreenQml", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, msg)); }
@KroMignon
Thank you.
I tried the way you taught me.
and i get the below error.
what is the problem???qrc:/main.qml:20:5: QML Connections: Cannot assign to non-existent property "onChangeScreenRequest"
qrc:/main.qml:21: ReferenceError: qmltocppcontrol is not defined
qrc:/main.qml:21: ReferenceError: qmltocppcontrol is not definedline 20 and 21 is...
line20 ---> target: qmltocppcontrol
line21 ---> onChangeScreenRequest: {and current, i try to the google search continually...~~wow... ~~
I am solving it a little bit. However, another problem came out..................omg...qrc:/main.qml:28: ReferenceError: varData is not definedConnections { target: qmltocpp_id onChangeScreenRequest: { console.log("onChangeScreenQml:" + varData); qmltocpp_id.controlEvent(0); //0 = EVENT_APP_EXIT } }
varData is parameter about signal ...
i want to use the below parameter of code..void QmltoCppControl::nextScreen() { std::cout << "void QmltoCppControl::nextScreen() :: "<< std::endl; QVariantList varData; varData.clear(); varData << "test"; emit changeScreenRequest((QVariant)varData); }
wow.... solved it!!!
Thanks @KroMignon !! And thanks to everyone who helped!!!! -
@LeeK You are very confusing in your comments, I don't really understand your problem...
What do you want to do???
As I have understand, you want to connect a object created from C++ with a QML code. Is this correct?
For me:- the c++ object was qmltocppcontrol created in main.cpp
- the QML instance was qmltocpp_id created in main.qml
If this is not what you want to do, please be clear in what is to task you want to do!
regards
-
//main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include "myclass.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; myClass mClass; QObject *rootElement = engine.rootObjects().first(); QObject::connect(&mClass,SIGNAL(mySignal(QVariant)), rootElement, SLOT(qmlFunction(QVariant))); return app.exec(); }
//myClass.h #ifndef MYCLASS_H #define MYCLASS_H #include <QObject> #include <QVariant> #include <QTimer> #include <QTime> class myClass : public QObject { Q_OBJECT public: explicit myClass(QObject *parent = nullptr) :QObject(parent) { QTimer *t = new QTimer(this); connect(t, &QTimer::timeout, this, [=]()->void{ emit mySignal(QVariant::fromValue(QTime::currentTime().toString("hh.mm.ss"))); }); t->start(1000); } signals: void mySignal(QVariant msg); public slots: }; #endif // MYCLASS_H
//main.qml import QtQuick 2.12 import QtQuick.Window 2.2 Window { id:rootWindow width: 400 height: 250 visible: true function qmlFunction(msg) { console.log(msg) myText.text = msg; } Text { id:myText anchors.centerIn: parent text: qsTr("text") } }
-
Hi @LeeK , i dont know how you tried it, there is no way in which it will not work, i guess you must have missed passing a paramter or some silly mistakes. And the code which you have posted is completely different from what you had asked, you actually wanted to connect a signal to a function in qml and when i asked you have seen the Q_PROPERTY documentation, you told me yes you have seen, if you had seen Q_PROPERTY documentation you would even stumbled upon Connections documentation, please be clear on what is your requirement.
-
@KroMignon
Thank you.I am sorry for the confusion in my comments.
I solved the problem in the way that you suggested.
Thank you.@J-Hilk
Thank you.
I solved the problem. but, additionally i will try to the way that you suggested.@Shrinidhi-Upadhyaya
Thank you.
I don't know what you mean.
I did not know the part of the mistake or the wrong parameter you mentioned. So I asked the question.
I have already solved this problem with the help of others.