Dynamically create a whole new QML object from C++
-
wrote on 5 Sept 2016, 09:30 last edited by
Hello everyone,
I have a QML component Foo defined it its own file foo.qml. In my QtQuick app, I need to dynamically create instances of this component as a respond of a user action. I was able to do it using Qt.createQmlObject().
Now I want to have a matching C++ object with exposed properties/methods so when the QML component Foo is changed, its C++ equivalent is updated. To do so, I have created a C++ class FooModel that subclasses QtQuickItem and registered my C++ new type using qmlRegisterType().
My problem is : I want to dynamically instanciate FooModel and as a result, have a Foo component to be created in the QML side of the application, so no more use of Qt.createQmlObject(). And when I say instanciate, I mean to fully define the Foo component in my C++ object, and not loading foo.qml using QQmlComponent.create(). The idea behind this is to get rid of the foo.qml file.
I looked into the documentation and the Internet, but I cannot find any example that matches my need.
So my questions are :
-is it possible to fully create a QML component from C++,? Something like :Rect* rect = new Rect(QMLRoot); Text* text = new Text(rect); MouseArea* marea = new MouseArea(rect);
-if it is possible, how can you handle events, for example how do you plug to MouseArea events?
I have the feeling that I am trying to do something that is not possible, but I am not a Qt expert so I am looking for your advices.
Thanks for any help! -
wrote on 5 Sept 2016, 21:35 last edited by
Defining a visual QML component in C++ is done by inheriting from QQuickItem. Look for the "Custom Scene Graph Items" section.
Unfortunately most (all?) of the building blocks such as Rectangle and Text lack public C++ APIs. Is there a reason behind the avoidance of QQmlComponent?
-
wrote on 6 Sept 2016, 06:46 last edited by
Hello and thanks for your answer.
The reason I want to avoid loading an existing QML file is because I want this kind of relationship: each instance of my C++ object will have its own instance of QML object. By doing so, I want all the QML properties to be linked to the C++ properties of the instance.I know that I can expose a C++ object into the QML context with:
QQmlApplicationEngine engine; MyObject sc; engine.rootContext()->setContextProperty("myobject",&sc);
And then in my Foo.qml file use it to access the Q_PROPERTY I have declared in the class MyObject:
Rectangle{ width:sc.width }
But for me (and I may be wrong), doing this will expose a global "myobject" variable that will be used by every instances of Foo.qml that I will dynamically create with Qt.createQmlObject or Qt.createComponent. And I want a one-instance-to-one-instance system.
I hope I made myself clear :/
-
wrote on 6 Sept 2016, 07:29 last edited by
I think that I understand. For some nontrivial number of QML objects, the goal is to bind to a unique property whose value can be controlled from C++. SetContextProperty does indeed create a global variable that will have the same value for all items that reference it.
It sounds like these C++ objects are sources for properties, but probably don't have visual properties.
One option is to compose the visual portion in QML, with a QObject-derived, qmlRegisterType() registered object as the source for the C++ properties.
MyItem.qml
import org.examples 1.0 Rectangle { CppObj { id: cppObj } Text { text: cppObj.text } }
main.cpp
class CppObj : public QObject { Q_OBJECT Q_PROPERTY(QString text ...) public: CppObj(QObject * parent = nullptr); ... } ; CppObj::CppObj(QObject *parent) : QObject(parent) { // register the object instance or otherwise initialize properties } int main() { ... qmlRegisterType<CppObj>("org.examples", 1, 0, "CppObj"); // Now load the root document ... }
If this works for the use case, QQmlParserStatus might be of interest.
-
wrote on 6 Sept 2016, 07:58 last edited by
Hello,
Just to be sure, in your example, in which context do you dynamically create the QML component? In the C++ context or the QML context? Is that what you mean in the constructor?I will have a look at QQmlParserStatus, never used that class before so I may ask you some questions about it too.
-
Hello,
Just to be sure, in your example, in which context do you dynamically create the QML component? In the C++ context or the QML context? Is that what you mean in the constructor?I will have a look at QQmlParserStatus, never used that class before so I may ask you some questions about it too.
wrote on 6 Sept 2016, 08:18 last edited by@bguivarch said in Dynamically create a whole new QML object from C++:
Hello,
Just to be sure, in your example, in which context do you dynamically create the QML component? In the C++ context or the QML context? Is that what you mean in the constructor?It doesn't matter. After the type registration, any use of MyItem will instantiate an instance of CppObj. The CppObj's parent is the MyItem instance, and will be destroyed when MyItem is.
The comment in CppObj::CppObj() is a place holder for doing something based on the 1:1 QML to C++ object relationship previously mentioned. I wasn't able to come up with a better, concise example construct based on the problem description.
-
wrote on 9 Sept 2016, 09:07 last edited by
Ok thanks for your help.
1/7