Handling of objects and types between C++ and QML
- Summarized from: http://lists.qt-project.org/pipermail/development/2012-May/004049.html
- Added by sivang [qt-project.org]
- Discussion started in an attempt to understand how objects are owned and are made available to QML through C++, and their maintenance thereafter.
Safely exposing QSharedPointer objects to QML
Q: How can we expose objects governed by QSharedPointer to QML safely? (Assume that we are talking about a pointer to a QObject)
Currently, QML isn’t aware of QSharedPointer and friends, but internally uses its own guard-types to react to QObject deletion. If you want to ensure that the engine won’t delete the QObject you pass in, you need to explicitly set the ownership of the QObject to CppOwnership (there’s a QQmlEngine function to do so). Alternatively, if the QObject has a parent (ownership parent) set, the engine won’t delete it.
A: You need to observe these rules:
- You need to be able to guarantee the life of your QObject beyond the life of the QDeclarativeEngine. [ Reason: It was suggested in the mailing-list thread that the engine could cache a reference to the object ]
- It is too dangerous to mix QSharedPointer ownership with the QObject parent/child ownership.
- [ Should the referenced class inherit QObject? ]
Thus this is the only way to go about it:
- Call QSharedPointer :: data() to get a pointer to the referenced class;
- Make sure the QML engine doesn’t assume ownership: QDeclarativeEngine :: setObjectOwnership (P). This step is necessary since the only other way of keeping the engine from assuming ownership would be to give the object a parent, which is out of the question since the shared pointer already has ownership.
- Hand over the raw QObject pointer to QML using either QObject :: setProperty or QDeclarativeContext :: setContextProperty
Ways of exposing references to QML and their effect on ownership
- The QML engine respects normal QObject parenting.
- By calling QDeclarative::setRootContext (ownership not transferred: http://qt-project.org/doc/qt-4.8/qdeclarativecontext.html#setContextProperty).
- no ownership change.
- By calling QObject::setProperty on the instantiated component (ownership?)
- no ownership change
- By QML calling a method on a C++ object and getting a response (ownership IS transferred to QML if and only if the QObject has no parent)
- ownership change if ownership semantics were not previously explicitly set; e.g.
- By QML accessing a Q_PROPERTY on a C++ object (ownership?).
- no ownership change
Issues arising from type handling of objects exposed; relevant when specifying properties in QML
- It builds type information from the loaded component set, and enforces type safety when assigning to properties of those types.
Crossing C++ / QML boundaries issues.
- Q: What are the exact mechanisms that governs value conversion from one space to another?
- There are quite a few different types for which we do this (sequence types such as QList<int> etc, internal implementation detail classes for which we need to intercept symbol resolution, etc).
Special semantics for null and undefined
- if “undefined” is assigned to a QVariant property which is Reset-able, we reset the property.
- Null is generally treated as a null-ptr when assigned to QObject-derived-type properties, but otherwise may fail, depending on the property type.
Improvements in the works (Qt5)
- Simpler and more intuitive way to expose Collections (QList, QMap, QHash, QSet) to QML:
- At the moment, QList of int, bool, qreal, QString, QUrl.
- To avoid the type conversion edge cases, thoughts to use more of a property var in the implementation.