Expose C++ value to QML's shared JavaScript library
-
How can I get a value from C++ in QML's stateless JavaScript (ie .pragma library) ? I use the following method to access C++ value from QML and non-stateless JavaScript file:
@
#define APP_NAME "myApp"int main(int argc, char *argv[]){
QApplication app(argc, argv);
...
QDeclarativeView view;
view.rootContext()->setContextProperty("APP_NAME", APP_NAME); // expose to QML root context
...
}@Then I can access the value from QML/JS using APP_NAME but I can't access in stateless JavaScript file. How to expose C++ value to stateless JavaScript file?
-
Hi,
Firstly, despite what the old documentation said, .pragma library js resources are not stateless; they're definitely stateful. They are shared context libraries, however, which means that importing them multiple times does not result in each imported version having its own context.
In practice, this means that the .pragma library doesn't ever inherit context from the importing scope, because it might be imported multiple times. Thus, the root context of a .pragma library js resource is a top-level (or orphan) context - not the root context of the application.
To get things from the application's root context into the shared JS context, you can pass them as parameters:
@
.pragma libraryvar app_name
var isInitialized = false
function initialize(appName) {
isInitialized = true;
app_name = appName;
}// whatever other code, below...
@This can then be called from your top-level QML application context:
@
import "shared.js" as MySharedItem {
Component.onCompleted: if (!MyShared.isInitialized) MyShared.initialize(APP_NAME);
}
@I hope this helps!
-
Thanks for your suggestion.
But I have lot of constant value that I need to pass to JavaScript library from C++, using the above method will definitely make the code looks poor (need to expose every value to QML then pass to JavaScript). Do you have any better suggestion? :)
-
You can create one single QObject in C++, with a whole bunch of properties.
EG:
@
class MyConstantsContainer : public QObject
{
Q_OBJECT
Q_PROPERTY(int someConstant READ someConstant WRITE setSomeConstant NOTIFY someConstantChanged)
Q_PROPERTY(QString otherConstant READ otherConstant WRITE setOtherConstant NOTIFY otherConstantChanged)
// ... etcpublic:
MyConstantsContainer(QObject *parent) : QObject(parent) {}
~MyConstantsContainer() {}int someConstant() const { return m_someConstant; } void setSomeConstant(int c) { m_someConstant = c; emit someConstantChanged(); } // etc...
private:
int m_someConstant;
};
@Then, in your main.cpp or other entrypoint, instantiate the object, set the constant properties, and set it as a root context property (eg, "constants").
Then in your main QML file, call the init function, passing the "constants" object to the pragma library. Store a reference to the object (eg, var constantsObj; function init(constants) { constantsObj = constants; }From then on, you'll be able to access the constants via: constantsObj.someConstant; etc.
Cheers,
Chris. -
Thanks Chris, but I have a question:
If I pass a QObject to a shared JavaScript library, is the pointer of the QObject being pass or copy of the QObject? If I change the value in the QObject will the object that I keep in the shared JavaScript library will change as well?
Also, in a shared JavaScript library, I can access to the Qt namespace and function (eg. Qt.formatDateTime()). Is it possible for me to achieve that?
-
A pointer to the QObject is what will be passed, internally. So, yes. And yes - the orphan context spawned for the library import is a clean copy of the global context which includes the Qt object, if I recall correctly, so you will have access to the Qt object and its functions.
Remember: if in doubt, try it! QML is great in that it's simple to iteratively try things and see what happens. You'll learn a lot about how QML works from exploring and trying different things.
Cheers,
Chris. -
Thanks Chris, I will try :)
1/7