Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Insert QML objects from C++ without QQmlApplicationEngine



  • Hello,

    I have two questions, a concrete one and a more general one about my approach.

    I'll start with the setting, as it is now.

    I need to create a custom QML component dynamically. This component is stored in a QML file on disk and I already managed loading it using a Loader. This components gets data from C++ objects. I instantiate those objects before loading and announce them to the engine using context properties. This approach is still static though and I want to be able to load an unknown number of this qml object. I briefly looked at the QML dynamic scene example, but I am unsure how fitting this example is for my scenario. The Scene should not change on a button click (which would be purely QML), but as soon as a serial device is attached (which is C++ with signals). Also, the QML objects have C++ properties and the example does not deal with this.

    Another problem that comes to mind is that I need multiple instantiations of the custom component. Setting the C++ objects using context properties would not be unambigious anymore. So, I found the following approach ( see the answer of that question ): https://stackoverflow.com/questions/23613936/c-qml-how-to-define-and-handle-multiple-contexts-for-dynamically-created-comp . Based on that, my current approach looks like this:

       /** get "anchor" points */
       QQmlEngine* engine = ...;
       QQmlContext* rootContext = engine->rootContext();
       QQmlContext* childContext = new QQmlContext(rootContext);
       QObject *rootGrid = engine->rootContext()->findChild<QObject*>("rootGrid");
    
    
        /** Set up controllers */
        A* obj = new A;
    
        childContext->setContextProperty("control", obj);
    
        QQmlComponent comp(engine, QUrl("qrc:/mycomponent.qml"));
        QQuickItem* compInstance = qobject_cast<QQuickItem*>(comp.create(childContext));
    
        compInstance->setParent(rootGrid);
    

    I want to place the new component in the component rootGrid which is a GridLayout.

    Now the problem is that rootGrid is a nullptr. I found that root objects can also be obtained from a QQmlApplicationEngine, but I cannot use anything else but a QQmlEngine. So: How can I get a root item instead? I do not believe I can create the QML objects from QML itself, due to the context properties that I also cannot avoid.

    Secondly, am I taking the correct approach? Basically, my situation is as follows.

    I have n data sources. I don't know n and n can change during execution. There is an interface class A that accepts a data source and manages the graphical representation in the QML object (a controller, that I currently set by a context property). This class also needs some instantiation, creating it is not enough. During instantiation, it connect to several other classes that also need to be created. Class B emits a signal as soon as I need a new instance of my custom control on the UI. Due to the complexity on the C++ side, I chose to handle it in C++ - but maybe, it is actually easier to do in QML?



  • Hello,

    with the help of @KillerSmath (thank you so much :D), I managed to solve the problem.

    Apparently, I cannot get the root item using the QQmlEngine but I was able to get a root item from the QQuickWindow. I hope this information might be useful for others, so I will not delete the question.


Log in to reply