Dynamic objects and QML bindings



  • Hello,

    I'm just starting to learn QML and I don't understand a point. I read some tutorials to understand how the binding between QML and C++ objects but dynamic objects creation stays a little fuzzy...

    Here's my problem :

    I want to draw some objects on the map. I don't know their number in advance. So I create my object in C++ and add this line for each object :

    @viewer.rootContext()->setContextProperty("objectNameVisibleInQML", myObject);@

    and then in QML I can do, for example :

    @MyItem{
    position: objectNameVisibleInQML.position
    }@

    This works perfectly when I create manually the object in C++, giving them "hard coded" names. But how can I do, for example :

    -Generate 10 objects dynamically in C++ (with perhaps name generation like "myMapItem1, myMapItem2, etc..." pour QML binding)
    -Generate the 10 graphics items dynamically in QML corresponding to these 10 objects and have them binding with (because as I don't know the QML name in advance, I cannot put it in the code...) ?

    I think I'm missing something but I can't find examples for that problem

    Hope someone can help :)


  • Moderators



  • Hello and welcome to qt-project.org,

    you could iterate trough all children and pass your object to them. For dynamically creating qml items i would recommend you to use a ListModel.

    For further information please read:
    "Location Children From Cpp":http://qt-project.org/doc/qt-4.8/qtbinding.html#locating-child-objects
    "ListView":http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-listview.html



  • Hello,

    Thanks for your answers. I'll watch for the links if I can find all that I need :). And by the way when you're talking about accessing the children, you mean QML objects from C++ ? Is that not against the QML philosophy ?



  • Ok I think I get the point for dynamic creation from QML. But I still not understand how I can make the link (for properties) between the logic c++ object and the graphic qml object.

    Let's take back to my first scenario :

    -I create a list of object from a ListModel in QML, using dynamic creation
    -for each qml object creation, I send a signal to an object manager in C++ which will create a logic c++ object

    Now I want to expose a property of my c++ object to my qml object so if this property change in the c++ object, it'll change in the qml object too. As far as I can read on this page http://qt-project.org/doc/qt-4.8/qtbinding.html#locating-child-objects (on Modifying Properties part), the only way to do this is to use @setContextProperty()@ BUT if it can be done in the c++ side but QML need the name given to this property on C++ side so :

    @Item{
    property: c++PropertyName.variable
    }@

    can be written.

    All of this to say that I still don't get how this is possible to expose those properties when you CAN'T know the name given on c++ side in advance...



  • You can assign bindings imperatively, via:
    theProp=Qt.binding(function(){return cppObject.someProp;});

    Note that bindings assigned this way are less optimal than bindings defined declaratively in QML.

    Cheers,
    Chris.



  • [quote author="Zanis" date="1392195170"]Hello,

    And by the way when you're talking about accessing the children, you mean QML objects from C++ ? Is that not against the QML philosophy ?[/quote]

    • Yes you can access QML objects from C++
    • No it's absloutely not against the QML philosophy.

    I would strictly do the frontend in QML and the backend in Cpp. That doesn't mean that there should be no communication between them.
    For example: If you've got a Label in QML and you want to text it's change based on some status in your Cpp-programm, you would need to pass the new text to the Label. That means your code access the Label as a QObject and sets it's text-property to the new text. Or you could just invoke a QML method which sets the Labeltext and pass your new text as a parameter. But both methods would need a straight communication between QML and Cpp. Also you can create your own components in QML and register them in QML so you can use them there or use setContextProperty() access or replace a named component.

    [quote author="Zanis" date="1392220297"]Ok I think I get the point for dynamic creation from QML. But I still not understand how I can make the link (for properties) between the logic c++ object and the graphic qml object. [/quote]

    It is pretty simple. Your Viewer has got a rootContext() and a rootObject(). Lets take the rootObject:
    @QQuickView *view = new QQuickView();
    view->setSource(QUrl("YourQmlFile.qml"));
    QObject object = (QObject)view->rootObject();@
    The rootObject is your top-level object in qml and has got all other components as children. If you are searching for a children you should give it an objectName.
    @Rectangle {
    objectName: "myRectangle"
    // some code
    }@
    Now we search for our Rectangle using the function findChild().
    @QObject myObject = object->findChild<QObject>("myRectangle");
    if(object){
    // We got it :)
    }@
    Lets go ahead and set a property:
    @object->setProperty("propertyName", QVariant("Some Value :)"));@
    Passing a QVariant as a value isn't necessary at all since QML converts them to a type it understands.
    It's also easy to get a property:
    @QVariant ourProperty = object->property("propertyName");@

    [quote author="Zanis" date="1392220297"]As far as I can read on this page http://qt-project.org/doc/qt-4.8/qtbinding.html#locating-child-objects (on Modifying Properties part), the only way to do this is to use
    setContextProperty()[/quote]

    You can use the contextProperty() for that, too. If you've got for example an model in QML named myModel you could use rootContext().setContextProperty("myModel", modelFromCpp) to pass a model from Cpp to QML and replace myModel with it. There is a good example in the QT-Docs:
    @QQmlEngine engine;
    QStringListModel modelData;
    QQmlContext *context = new QQmlContext(engine.rootContext());
    context->setContextProperty("myModel", &modelData);

    QQmlComponent component(&engine);
    component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
    QObject *window = component.create(context);@

    Some helpful links:

    "QQmlContext":http://qt-project.org/doc/qt-5.0/qtqml/qqmlcontext.html#details
    "Embedding C++ Objects into QML with Context Properties":http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-contextproperties.html
    "Interacting with QML Objects from C++":http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-interactqmlfromcpp.html

    If you want to know how to access QML functions i would provide you a little tutorial for that, too.Feel free to ask if you have got questions.



  • For of all, sorry for the late reply. I've read your answer and it's a lot clearer for me now. I thought that it was "bad" to update QML directly from C++ but I was wrong. Anyway, thanks a lot for your explanation, I switched on an other part of the project for now, so I'll try to practice it as soon as I finish other stuff but if I have other questions on this subject, I'll come back :)

    Thanks again for your help !



  • You're welcome. Glad we could help you.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.