engine.rootContext()->setContextProperty is failing to add property
-
Hello, I'm trying to expose some C++ objects to my QML code, and it won't work. The object appears to be unrecognized in qml (it doesn't highlight a different color), and when I try and return engine.rootObjects(), the list is empty. If this is not how it should be working, then please let me know.
Here is my main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "updatescreen.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; UpdateScreen* screen = new UpdateScreen(); const QUrl url(u"qrc:/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); screen->init(); engine.rootContext()->setContextProperty("UpdateScreen", screen); if (engine.rootObjects().isEmpty()) { return -1; } engine.load(url); return app.exec(); }
My declaration of UpdateScreen.h as a Q_Object:
class UpdateScreen : public QObject { Q_OBJECT Q_PROPERTY(int foo READ getFoo WRITE setFoo NOTIFY fooChanged) public: explicit UpdateScreen(QObject *parent = nullptr); void init();
And my qml file trying to access the property:
Connections { target: UpdateScreen onFooChanged: { a.text = UpdateScreen.getFoo(); } }
Please let me know how I can fix this and get it working! Thank you!!
-
Hello, I'm trying to expose some C++ objects to my QML code, and it won't work. The object appears to be unrecognized in qml (it doesn't highlight a different color), and when I try and return engine.rootObjects(), the list is empty. If this is not how it should be working, then please let me know.
Here is my main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "updatescreen.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; UpdateScreen* screen = new UpdateScreen(); const QUrl url(u"qrc:/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); screen->init(); engine.rootContext()->setContextProperty("UpdateScreen", screen); if (engine.rootObjects().isEmpty()) { return -1; } engine.load(url); return app.exec(); }
My declaration of UpdateScreen.h as a Q_Object:
class UpdateScreen : public QObject { Q_OBJECT Q_PROPERTY(int foo READ getFoo WRITE setFoo NOTIFY fooChanged) public: explicit UpdateScreen(QObject *parent = nullptr); void init();
And my qml file trying to access the property:
Connections { target: UpdateScreen onFooChanged: { a.text = UpdateScreen.getFoo(); } }
Please let me know how I can fix this and get it working! Thank you!!
@jcdelve to complete @DBoosalis answer, you should also take care about QML naming convention.
I don't remember where I found this in Qt documentation, or if it is a JavaScript convention, but all type should (must?!?) be UpperCamelCase and all instances and methodes in lowerCamelCase.I would suggest you to change your code to:
engine.rootContext()->setContextProperty("updateScreen", screen);
And
Connections { target: updateScreen function onFooChanged() { a.text = updateScreen.getFoo() + ""; // to converter int into string } }
-
@DBoosalis
I update it in UpdateScreen.cpp:void UpdateScreen::setFoo(int rate) { foo = rate; emit fooChanged(); }
I made both your changes, but it still doesn't seem to recognize the QT Object and the application returns -1. Since I return -1, it would seem to imply that it's not adding the object correctly in the rootContext? But I'm not sure why...
-
Since it is not giving any object undefined error, it means that object is recognized. I don't see any issue with the object. I suspect that setting value is not right sequence. Where are you setting the value of foo variable ? When are you setting it ? May complete example will help here.
-
@jcdelve said in engine.rootContext()->setContextProperty is failing to add property:
if (engine.rootObjects().isEmpty()) {
return -1;
}This will not work. This method returns objects instantiated by the engine, using load() method, which you call later. It does not return context properties.
engine.rootContext()->setContextProperty("UpdateScreen", screen);
Only QML components should start with upper case. Try with
"updateScreen"
. -
@dheerendra Right now, I'm just doing it in the init() method that I call in main.cpp. I'm just trying to establish this functionality before actually implementing it how I need it.
void UpdateScreen::init() { setFoo(20); }
main.cpp
screen->init(); engine.rootContext()->setContextProperty("updateScreen", screen); if(engine.rootObjects().isEmpty()) { return -1; } engine.load(url); return app.exec();
@sierdzio I made that change following @KroMignon's post but it did not change anything
-
@jcdelve said in engine.rootContext()->setContextProperty is failing to add property:
if(engine.rootObjects().isEmpty()) {
return -1;
}remove that.
-
You call
init()
before your QML is loaded. ThefooChanged()
signal is fired long before your QML slot (Connections
) is ready to receive it.Invoke
init()
after some delay and it will work. -
@sierdzio
Good catch, that would definitely be part of the problem. However, the object is still not recognized in the qml file. Using QT Creator, the object I know should appear highlighted and italicized, but it's not. And when I try and call the .getFoo() function, it says it's not a function -
-
@JoeCFD That worked! I didn't realize I needed that for every single property.
I will say it still looks weird, because the object still looks like normal text instead of highlighted or whatever, but it works so I'm not complaining. Thank you! -
@KroMignon said in engine.rootContext()->setContextProperty is failing to add property:
a.text = updateScreen.getFoo() + ""; // to converter int into string
You don't need to make
getFoo()
invokable! Just call the property instead of a function:a.text = updateScreen.foo
-
Do it declaratively like so:
// ... Label { text: UpdateScreen.foo }
it will automatically update when the fooChanged signal is emitted.
DoingQ_INVOKABLE int getFoo();
is ugly. -
Interesting. By all other conventions of coding standards, it's bad practice to have a variable directly accessible like that... Is there a reason QT/QML prefers that over doing an invokable getter?
@jcdelve said in engine.rootContext()->setContextProperty is failing to add property:
Interesting. By all other conventions of coding standards, it's bad practice to have a variable directly accessible like that... Is there a reason QT/QML prefers that over doing an invokable getter?
Please read up on how Q_PROPERTY system works. You are not accessing a variable, you are accessing a property. QML (via Meta Object System) will use the getter / setter you provide in Q_PROPERTY declaration. It will not access the variable directly.