Unsolved How to set a non-global context property for a single QQmlComponent?
-
This was previously asked here, but didn't get any responses: Setting context property for individual QML UI element
Surely there must be a way to set a context property on a single component without having to set it globally on the entire engine? Indeed, the documentation is silent on this point.
Help??
-
@patrickkidd I don't think this is possible.
Assigning stuff to the root context is supposed to be global for all qml files.
If you want a c++ class that is independent from other aktive instances of your c++ backend and only access it via qml, than you can do that via
qmlRegisterType
If you want it to access an instance from other c++ instances and only access it from specific QML files, than a Singelton is your only way viaqmlRegisterSingletonType
-
@J.Hilk said in How to set a non-global context property for a single QQmlComponent?:
@patrickkidd I don't think this is possible.
Assigning stuff to the root context is supposed to be global for all qml files.
If you want a c++ class that is independent from other aktive instances of your c++ backend and only access it via qml, than you can do that via
qmlRegisterType
If you want it to access an instance from other c++ instances and only access it from specific QML files, than a Singelton is your only way viaqmlRegisterSingletonType
I am wondering about exposing object instances, not types, to a single QQmlComponent.
-
@patrickkidd than take a look at his section
https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterSingletonType
an example how to register and access the class - taken from my current project
//main.cpp qmlRegisterSingletonType<BluetoothDevice>("BluetoothBackend", 1, 0, "Bluetooth", BluetoothDevice::instance); //in my qml file import BluetoothBackend 1.0 .... ListView { id:lView anchors.fill: parent model: Bluetooth.devices .... onClicked:{ Bluetooth.connectToDevice(modelData.deviceAddress) } //the c++ callback, because the docu is not that great in that instance static QObject *instance(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(scriptEngine) if(BluetoothBackend) return BluetoothBackend; BluetoothBackend = new BluetoothDevice(); engine->setObjectOwnership(BluetoothBackend,QQmlEngine::CppOwnership); return BluetoothBackend; }
-
@J.Hilk said in How to set a non-global context property for a single QQmlComponent?:
@patrickkidd than take a look at his section
https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterSingletonType
an example how to register and access the class - taken from my current project
//main.cpp qmlRegisterSingletonType<BluetoothDevice>("BluetoothBackend", 1, 0, "Bluetooth", BluetoothDevice::instance); //in my qml file import BluetoothBackend 1.0 .... ListView { id:lView anchors.fill: parent model: Bluetooth.devices .... onClicked:{ Bluetooth.connectToDevice(modelData.deviceAddress) }
I'm sorry, that is still not what I am asking. I am specifically asking how to set a context property that only one component can see. For example, I would set one object as a "dateModel" context property on one component, and different object to the "dateModel" context property on another component.
-
@patrickkidd
again not possible with contextProperty -
@patrickkidd As already answered, there is no way to use the context property mechanism to do what you want. However, if you expose a C++ class to QML via
qmlRegisterType
, you can create an instance of that type in your QML component:class MyType: public QObject { Q_OBJECT // properties Q_PROPERTY(bool isValid READ isValid WRITE setIsValid NOTIFY isValidChanged) ... public: //methods Q_INVOKABLE void doSomething(...); ...
// QML component Item { MyType { id: myType isValid: false ... } // reference properties and methods as required: // myType.isValid // myType.doSomething(...)
The point is that you have the freedom to do what you want in your C++ object. You could expose a model as a property of it for example.
Also, in this way you are in control of what is visible in your component. Note that this naturally instantiates an instance of your C++ object per QML component instance, but you have room for manoeuvre in the C++ backend. If, for example, you want what would effectively be a singleton to share between the QML components that reference it you could implement it as a
Monostate
-like class. -
You arguments make sense, and it seems clear from the flow chart that setting up a context specific to the component is not possible. Further, it probably is better practice to just create a
var
property in the component and assign theQAbstractItemModel
to it, if That model actually must be created in C++ (for example if it is handed to one or more other components).Just for my own understanding, I did get a reply from the Qt-interest mailing list that you can create a sub-context like the following snippet, though this isn't possible with a
QQuickWidget
at current. Also, to my knowledge there is no way to show an item created withQQmlComponent::create
in a widget....I could be wrong though. Doesn't this create a sub-scope as in the original question though?QQmlContext *context = new QQmlContext(engine->rootContext()); QQmlComponent *comp = new QQmlComponent(mySource); context->setContextProperty("myModel", myModel); comp->create(context);
-
I have been pursuing the route of setting a property on the root
QQuickWidget
component. Qml's property inheritance makes it so that all child components can see that property set on the root, so this works in theory.One reason I was avoiding this was that there would be a delay between creating the root component and setting the property and all of the references to the property would fail, particularly if I initialize the root property to null. I imagine the workaround is to initialize the property value to a dummy object or uninitialized object of the same class, and then overwrite it with
QQuickItem::setProperty
after theComponent
is initialized from qml source.Now, the problem I am running into with this solution is that the dummy objects are not destroyed when I overwrite them with
QQuickItem::setProperty
. I checked this by starting a C++ timer on them with a print statement. But this could be because I am using PyQt and a reference is still around somewhere (although the C++ object should have been deleted anyway...) or becauseQObject::startTimer
keeps the object around. Or maybe I should just ignore these "leaked" objects anyway.At any rate, this looks to me like an important design principle to nail down.