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

accessing aggregates (QVector of a struct)



  • Hi all -

    I'm in need of a bit of guidance here. I've collected some data that I need to represent in a QML screen. I've put the data into a QVector of this struct:

    struct BottleInfo {
        float volume;
        float amountNeeded;
        int position;
        std::string name;
        ReagentBottleType bottleType;
    };
    typedef QVector<BottleInfo> BottleList;
    

    but this is totally up to me -- I can store it another way if it makes QML access easier.

    The vector is small (currently known to be 16 elements).

    So:

    1. is this a good way to store data that needs to be QML-accessible?
    2. what is the syntax for accessing members of an element of a vector?

    Thanks...



  • I'm trying to use this example:

    enum class ReagentBottleType;
    struct BottleData {
        Q_GADGET
        float m_volume;
        float m_amountNeeded;
        int m_position;
        std::string m_name;
        ReagentBottleType m_bottleType;
        Q_PROPERTY(float volume MEMBER m_volume)
        Q_PROPERTY(float amountNeeded MEMBER m_amountNeeded)
        Q_PROPERTY(int position MEMBER m_position)
        Q_PROPERTY(std::string name MEMBER m_name)
        Q_PROPERTY(ReagentBottleType bottleType MEMBER m_bottleType)
    };
    

    I define a BottleList in another class, but when I attempt to access properties (eg volume) from a method of that class, I get a "no member named 'volume'" error. Do I need to call a setContextProperty() for the BottleList object? That doesn't make sense to me.



  • Still tinkering...

    struct BottleDataCC {
        Q_GADGET
        ...
    };
    Q_DECLARE_METATYPE(BottleDataCC)
    

    I was hoping that this would allow me to use the BottleDataCC type in my QML, but it's warning that it's an unknown type. Can someone show me what I'm forgetting here? (Hopefully not too many things)

    Thanks...

    EDIT: I guess it might help if I showed my QML as well:

      function getBottleData(index) {
          return changeConsumablesViewModel.getBottleData(index)
      }
    


  • @mzimmers hi

    // bottle struct with Q_GADGET macro
    struct Bottle {
        Q_GADGET
        Q_PROPERTY(int volume MEMBER volume)
      public:
        Bottle(){volume=55;}
        int volume;
    };
    
    // a class that will manage a list of Bottles. Expose an object from this class to you qml 
    class User : public QObject { 
        Q_OBJECT
    public:
        Q_INVOKABLE QVariant getBottleData (int ind){
            return QVariant::fromValue(bottleList[ind]);
        }
        User (){
            bottleList <<  QVariant::fromValue(Bottle()) << QVariant::fromValue(Bottle());
        }
        
      public slots:
        QVariantList getBottleList() {     
            return bottleList;
        }
    private:
         QVariantList bottleList;
    };
    

    then in QML you can

           var bottle  = user.getBottleData(0)
           console.log(bottle.volume)
    


  • @LeLev thank you for the response; this is helpful. I do have a few follow-up questions:

    1. I'd like to make this class usable by other C++ classes. How do I return a BottleList from my QVariantList?
    2. your getBottleList() declares bottleList, which is also a member variable. Is this correct?
    3. I haven't gotten to this point yet, but I'm not clear on how the QML accesses the members of the BottleData object (for example, the volume). Do I use the property for this?

    Thanks again...



  • @mzimmers said in accessing aggregates (QVector of a struct):

    your getBottleList() declares bottleList, which is also a member variable. Is this correct?

    it's a mistake from me,obviously it should return the member variable QVariantList bottle List, and not declare anything . I will correct it

    @mzimmers said in accessing aggregates (QVector of a struct):

    I haven't gotten to this point yet, but I'm not clear on how the QML accesses the members of the BottleData object (for example, the volume). Do I use the property for this?

    please take time to read my answer, i did show an example of usage in qml

    @mzimmers said in accessing aggregates (QVector of a struct):

    I'd like to make this class usable by other C++ classes. How do I return a BottleList from my QVariantList?

    i don't know what do you mean here sorry, what class are you talking about ?



  • Do your views need to react to changes in the data?
    The list might be appropriate as a property.

    Is the data updated all at once?
    Yes, then you can return the QVariantList as a property.
    No, then the list might be more appropriate as a model. This will allows updates to rows to be independent of each other.

    You can return a model as a qvariant this way: QVariant::fromValue(customModel) or as a QAbstractItemModel*. The latter is in the meta object system that qml can recognize.

    The reason I show the QVariant::fromValue is because I needed to return a model from a model in the data() call in my code. Something I just figured out.

    Also, this page might be helpful to know what is by default accessible to QML from C++.



  • Let me back up a bit: for this overall effort, there are three distinct (though overlapping) efforts:

    1. to collect the (current) information about the fill levels in 16 bottles in a rack. This is purely a C++ effort, and I've got it working.
    2. to put the information into a form that is available to QML.
    3. to render the information on a QML screen.

    To answer fcarney's question, let's assume that the view should indeed be dynamic. I can update all the information on demand (from C++, which is adequate).

    In my C++, I'd like to maintain a BottleList (as opposed to a QVariantList) for debugging purposes only. (Maybe there's a way to meaningfully examine the contents of a QVariantList in gdb, but I don't know of it.) I'm assuming that the QML needs a QVariant, right? I think it would be easier to implement a function that casts the list to a QVariantList for the QML, but I'm interested in others' opinions on this.

    Thanks...



  • The most basic would be a QVariantList that is a property. It would have a signal so that when the list is changed then the C++ can notify view. This will require a QVariantList to be built every time anything changes. For 16 items this is probably not a big deal. Keep your BottelList as is. The function that returns the values for the property can convert the entire list. The code that makes changes to the BottleList would need to fire the signal on changes.



  • Thanks for the information, guys. I'm making progress, but still can't quite connect all the dots. I've created a BottleList class, with a method:

    QVariantList BottleList::getBottleListQv() {
        QVariantList qvl;
        BottleData bd;
        for (int i = 0; i < NBR_BOTTLES; ++i) {
            bd = getBottleData(i);
            qvl.append(QVariant::fromValue(bd));
        }
        return qvl;
    }
    

    Another class ChangeConsumables creates an instance of BottleList.

    from my QML file:

            function getRackData() {
                var bottleRack = changeConsumablesViewModel.getBottleListQv()
                return bottleRack
            }
            Bottle {
                id: bottle1
                cellText: "W7"
                cellColor: "red"
            }
    

    I have 16 entries similar to bottle1.

    So, what I'm missing is...how to replace the hard-coded "W7" with the name field from the BottleData struct in my BottleList class?

    Thanks.


  • Moderators

    You can refer to the object by id. Like this:

    function loadRackDataFirst() {
        bottle1.cellText = changeConsumablesViewModel.getBottleListQv()[0].name
    }
    

    However you should convert to QString.



  • Repeater {
      model: changeConsumablesViewModel.getBottleListQv() // or use property, a property will have a signal to update if the list changes
      Bottle {
        cellText: modelData.name
      }
    }
    

    If you want more interaction then a model might be more appropriate.

    modelData Search for modelData on that page to understand where it comes from.



  • @kshegunov the "name" field isn't accessible as I've currently implemented it. I think I may have over-designed this. I've made several changes since my earlier posts, so let me recap my code:

    The struct:

    struct BottleData {
      Q_GADGET
    public:
      uint32_t m_volume;               // amount in bottle (in uL)
      uint32_t m_amountNeeded;         // amount needed for synth (in uL)
      int m_position;                  // still figuring this one out
      std::string m_name;              // name of the reagent
      ReagentBottleType m_bottleType;  // bottle type.
      Q_PROPERTY(uint32_t volume MEMBER m_volume)
      Q_PROPERTY(uint32_t amountNeeded MEMBER m_amountNeeded)
      Q_PROPERTY(int position MEMBER m_position)
      Q_PROPERTY(std::string name MEMBER m_name)
      Q_PROPERTY(ReagentBottleType bottleType MEMBER m_bottleType)
    };
    Q_DECLARE_METATYPE(BottleData)
    

    The class:

    typedef QVector<BottleData> BottleDataList;
    
    class BottleList : public QObject
    {
        Q_OBJECT
    private:
        BottleDataList m_bottleList;
    public:
        explicit BottleList(QObject *parent = nullptr);
        Q_PROPERTY(QVariantList qvl READ getBottleListQv)
        QVariantList getBottleListQv();
        ...
    

    From reading the docs, I was under the impression that I wouldn't need a getter for the fields in the struct, because I used the MEMBER macro. Did I misinterpret this?



  • @fcarney that looks really powerful. The complete definition of each model is like this:

            Bottle {
                id: bottle1
                cellX: 25
                cellY: 105
                cellHeight: 75
                cellWidth: 75
                bottleScaleFactor: scaleFactor
                cellText: "W7"
                cellColor: "red"
            }
    

    If I use the repeater to load the names, can I alter the individual bottles afterwards?

    Thanks...

    PS: I'm aware that there's a lot of ugly hard-coding in here; I was going to address that after I got the connections working.



  • If I use the repeater to load the names, can I alter the individual bottles afterwards?

    It only alters the copy given to the Repeater. It has no way to get that data back.

    I have not used Q_GADGETs before. What does it print out when you console.log(modelData)? Curious as what QML thinks that objects is.



  • @mzimmers said in accessing aggregates (QVector of a struct):

    From reading the docs, I was under the impression that I wouldn't need a getter for the fields in the struct, because I used the MEMBER macro. Did I misinterpret this?

    I "think" so. DOH! I meant to agree to the MEMBER macro doing that, not you misinterpreting this.



  • @fcarney my console.log isn't working for this app, so I can't tell you. I discovered Q_GADGET from some online searching; in simplest terms, it's a lightweight version of Q_OBJECT (no signals/slots).

    I'm not at all concerned with updating anything other than my display. But now you have me wondering where I should really define all those values. (I would rather not use JSON, but that's probably the right way to do this.)



  • @mzimmers If you want your display to interact with the data then a full blown QAbstractListModel would be a better fit. Then each piece of the BottleData object could be its own role. With a setData routine you can edit that model.


  • Moderators

    @mzimmers said in accessing aggregates (QVector of a struct):

    Q_DECLARE_METATYPE(BottleData)
    

    is already done by the Q_GADGET so it's superfluous.

    Switch

    std::string m_name;
    

    to QString.

    Register the type with QML (qmlRegisterType) if you intend to create instances of it from there.

    From reading the docs, I was under the impression that I wouldn't need a getter for the fields in the struct, because I used the MEMBER macro. Did I misinterpret this?

    Nope, this is correct as far as I recall.

    If I use the repeater to load the names, can I alter the individual bottles afterwards?

    I don't think so, but I'm a noobster with QML. I believe you can imperatively create the items like this (untested):

    Component {
            id: component
            Bottle { cellText: "default text" }
            onCompleted: changeConsumablesViewModel.getBottleListQv().forEach(element => function(element)  {
               createObject(parentItemId, { cellText: element.name });
            }, this);
    }
    

    or something akin.



  • OK, so why doesn't this work?

        Rectangle {
            id: rack
            function getBottleName(i) {
                return changeConsumablesViewModel.getBottleListQv()[i].m_name
            }
            Bottle {
                cellText: rack.getBottleName(0)// "W7"
            }
    

    I get this error on the line with the "return" statement:

    TypeError: Cannot read property 'm_name' of undefined


  • Moderators

    @mzimmers said in accessing aggregates (QVector of a struct):

    TypeError: Cannot read property 'm_name' of undefined

    Your property is called name, also check the elements you get in that array. Side note: you may need to wait for the component to be fully loaded before doing that (but take with a grain of salt).



  • @kshegunov said in accessing aggregates (QVector of a struct):

    @mzimmers said in accessing aggregates (QVector of a struct):

    TypeError: Cannot read property 'm_name' of undefined

    Your property is called name, also check the elements you get in that array.

    Tried with "name" -- same error.

    Side note: you may need to wait for the component to be fully loaded before doing that (but take with a grain of salt).

    Actually, I think you're on to it here. For some reason, the people who wrote this app (I'm just maintaining it) load all the QML files up-front, rather than as-needed. I think the problem is that this is an empty vector when this function is first called...I need to think of how best to handle that.


  • Moderators

    @mzimmers said in accessing aggregates (QVector of a struct):

    Actually, I think you're on to it here. For some reason, the people who wrote this app (I'm just maintaining it) load all the QML files up-front, rather than as-needed. I think the problem is that this is an empty vector when this function is first called...I need to think of how best to handle that.

    Check that through the console. If you want, you can try to wait for the component by adding[1]:

    Component.onCompleted: <js code to do w/e>
    

    [1]: https://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal



  • Okay, I tested it. I cannot get Q_GADGET to work so I used Q_OBJECT:
    class in main.cpp:

    using ReagentBottleType = int;
    class BottleData : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(int volume MEMBER m_volume NOTIFY somethingChanged)
        Q_PROPERTY(int amountNeeded MEMBER m_amountNeeded NOTIFY somethingChanged)
        Q_PROPERTY(int position MEMBER m_position NOTIFY somethingChanged)
        Q_PROPERTY(std::string name MEMBER m_name NOTIFY somethingChanged)
        Q_PROPERTY(ReagentBottleType bottleType MEMBER m_bottleType NOTIFY somethingChanged)
    public:
        BottleData(QObject* parent=nullptr)
            : QObject(parent)
        {
            connect(this, &BottleData::somethingChanged, [this](){
                qDebug() << "somethingChanged" << m_position << QString::fromStdString(m_name) << m_volume;
            });
        }
    
        int m_volume=0;               // amount in bottle (in uL)
        int m_amountNeeded=0;         // amount needed for synth (in uL)
        int m_position=0;                  // still figuring this one out
        std::string m_name="";              // name of the reagent
        int m_bottleType=0;  // bottle type.
    
    signals:
        void somethingChanged();
    };
    

    setting contextProperty in main.cpp for testing:

    TestObj testobj;
    auto context = engine.rootContext();
    context->setContextProperty("varlisttestobj", &testobj);
    

    QML to exercise the object in C++:

    Column {
            anchors.top: listview1.bottom
            Repeater {
                model: varlisttestobj.varList
    
                Row {
                    id: bottledelegate
    
                    width: 50
                    spacing: 20
    
                    Component.onCompleted: console.log(modelData, modelData.position, modelData.volume)
    
                    Timer {
                        interval: 1000
                        repeat: true
                        running: true
                        onTriggered: {
                            modelData.volume += 1
                        }
                    }
    
                    Text {
                        text: modelData.position
                        height: 20
                    }
                    Text {
                        text: modelData.volume
                        height: 20
                    }
                }
            }
        }
    

    QML did not like uint32_t at all. So you will have to find another type that it likes on that page with compatible QML types I linked earlier.



  • Oops, I forgot test object in main.cpp:

    class TestObj : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QVariantList varList READ varList NOTIFY varListChanged)
        //Q_PROPERTY(QObjectList objList READ objList NOTIFY objListChanged)
    
    public:
        TestObj(QObject* parent=nullptr)
            : QObject(parent)
        {
            for(int count=0; count<10; ++count){
                auto bottle = new BottleData();
                bottle->m_volume = count*10;
                bottle->m_position = count;
                m_bottleData.append(bottle);
            }
    
            emit varListChanged();
        }
    
        QVariantList varList(){
            QVariantList list;
            for(auto bottleData: qAsConst(m_bottleData)){
                list.append(QVariant::fromValue(bottleData));
            }
            return list;
        }
        /*
        QObjectList objList(){
            QObjectList list;
            for(auto bottleData: qAsConst(m_bottleData)){
                list.append(bottleData);
            }
            return list;
        }
        */
    
    
    signals:
        void varListChanged();
    
    private:
        QVector<BottleData*> m_bottleData;
    
    };
    


  • I didn't expect it to trigger the somethingChanged signal in the BottleData object.



  • Trying to assign to std::string didnt work either:

    modelData.name = "fred"
    

    error:

    Error: Cannot assign QString to an unregistered type
    

  • Moderators

    Okay, so here you go:

    types.h

    #ifndef TYPES_H
    #define TYPES_H
    
    #include <QObject>
    #include <QVector>
    #include <QVariant>
    #include <QVariantList>
    
    struct Bottle
    {
        Q_GADGET
    
        Q_PROPERTY(QString name MEMBER m_name)
        Q_PROPERTY(qreal size MEMBER m_size)
    
    public:
        QString m_name;
        qreal m_size;
    };
    
    class DataSource : public QObject
    {
        Q_OBJECT
    
    public:
        Q_INVOKABLE QVariantList getData();
    };
    
    
    #endif // TYPES_H
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include "types.h"
    
    QVariantList DataSource::getData()
    {
        return {
            QVariant::fromValue<Bottle>({ "First bottle", 0.75 }),
            QVariant::fromValue<Bottle>({ "Second bottle", 0.70 })
        };
    }
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.addImportPath(QStringLiteral("qrc:/"));
        QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url] (QObject * obj, const QUrl & objUrl) -> void {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    
        DataSource source;
        engine.rootContext()->setContextProperty(QStringLiteral("DataSource"), &source);
    
        qmlRegisterUncreatableType<Bottle>("Example", 1, 0, "Bottle", "");
    
        engine.load(url);
    
        return app.exec();
    }
    

    main.qml

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    
    import Example 1.0
    
    Window {
        id: mainWindow
        visible: true
        width: 300
        height: 200
        title: qsTr("Some title")
    
        Component {
            id: template
            Text {
                text: "defaultText"
            }
        }
    
        Column {
           Component.onCompleted: DataSource.getData().forEach(function(element) {
               template.createObject(this, { text: element.name });
           }, this)
        }
    }
    

    PS. QML is damn annoying ...



  • @kshegunov said in accessing aggregates (QVector of a struct):

    PS. QML is damn annoying ...

    Heh...no argument there, but if I'm reading the tea leaves correctly, it's here to stay.

    I understand your C++ code, but I'm still trying to figure out what your QML results in. What exactly is this doing?

    Component {
            id: template
            Text {
                text: "defaultText"
            }
        }
    
        Column {
           Component.onCompleted: DataSource.getData().forEach(function(element) {
               template.createObject(this, { text: element.name });
           }, this)
        }
    

  • Moderators

    @mzimmers said in accessing aggregates (QVector of a struct):

    I understand your C++ code, but I'm still trying to figure out what your QML results in. What exactly is this doing?

    Well, I'm leveraging the fact that the QML engine is a glorified object factory. You know the widgets' basics, so with QtQuick it's the same story, more or less. It goes roughly like this:

    1. All visual items are derived from QQuickItem, these include the stuff you see in the QML file definition like Text and Column.
    2. Component does not(!) derive from QQuickItem, it is a QObject (or rather QQmlComponent) that's supposed to create your QQuickItems by calling QQmlComponent::createObject and passing it the correct visual parent and maybe a set of property values.
    3. When you load a QML file, this is what the engine does - it reads and instantiates the component your file represents, hence it creates all the visual and non-visual items described in said file. It parents everything by the way the items are nested (think of it as a big QObject tree). All the visual items are (re)parented to the root QQuickItem so they get painted correctly.
    4. After the object tree's loaded and the objects are instantiated you get the completed signal emitted and propagated through your items (visual and non-visual), so you can do w/e.
    5. In the above code you attach to the completed signal, then you call the getData to retrieve the list of structs, then forEach of the elements of the array you execute the anonymous function. The function is a dummy mostly. It just needs to go get the reference to the template component (which isn't a visual item, as mentioned) and call it's createObject to create the Text item contained. The first argument of the method is the visual parent (which is the Column in this case) and the second parameter is the set of properties to pass along, which is just the text value retrieved from the structure.

    PS. This code's tested (unlike most of the snippets I provide) so you can directly plug it in your project/app and play with it as you wish.



  • @kshegunov OK, I think I understand 1-4. But where is the getData() function explicitly referenced/called? (I think your getData() is the equivalent to my QVariantList BottleList::getBottleListQv().)

    I still don't understand how to retrieve the information to use it in my bottle objects.

            Bottle {
                id: bottle1
                cellX: 25
                cellY: 105
                cellHeight: 75
                cellWidth: 75
                bottleScaleFactor: scaleFactor
                cellText: "W7" // how to replace this with something from getData()?
                cellColor: "red"
            }
    

    Thanks...



  • hi

    @mzimmers said in accessing aggregates (QVector of a struct):

    I still don't understand how to retrieve the information to use it in my bottle objects.

    the answer is

    @kshegunov said in accessing aggregates (QVector of a struct):

    In the above code you attach to the completed signal, then you call the getData to retrieve the list of structs, then forEach of the elements of the array you execute the anonymous function. The function is a dummy mostly. It just needs to go get the reference to the template component (which isn't a visual item, as mentioned) and call it's createObject to create the Text item contained. The first argument of the method is the visual parent (which is the Column in this case) and the second parameter is the set of properties to pass along, which is just the text value retrieved from the structure.

     Column {
           Component.onCompleted: 
        
            DataSource.getData().forEach(function(element) {//anonymous  function call for each object  returned by  getData()
             
               template.createObject(this, { text: element.name }); // create a qml object  using the template and pass  the value retrieved from the structure  ( text:element.name )
           }, this)
        }
    

    Please make an empty project and test one of the examples given by @kshegunov @fcarney or me



  • @LeLev (et al): kshugenov's example does indeed work. I tried modifying it as follows:

        Column {
           property var myArray: []
           Component.onCompleted: DataSource.getData().forEach(function(bottle) {
    //           template.createObject(this, { text: bottle.name });
               myArray.push(bottle.name)
           }, this)
        Text {
            text: myArray[0]
        }
    

    But I get a runtime error that myArray is not defined. Am I supposed to use something other than a property var for this?

    Thanks...



  • @mzimmers said in accessing aggregates (QVector of a struct):

    myArray is not defined

    you need to assign the id of Column so you can access its properties from outside, it is qml basics

    Column {
    id :col
    property var myArray: []
    Text {
    text: col.myArray[0]
    }
    }

    @mzimmers said in accessing aggregates (QVector of a struct):

    kshugenov's example does indeed work.

    it does almost exactly the same thing as my very first example/answer.



  • @LeLev ah. So, now my code looks like this:

        Column {
            id: myColumn
            property var myArray: []
            Component.onCompleted: DataSource.getData().forEach(function(bottle) {
                //           template.createObject(this, { text: bottle.name });
                myArray.push(bottle.name)
            }, this)
            Text {
                text: myColumn.myArray[0]
            }
            Text {
                text:myColumn.myArray[1]
            }
            Text {
                text: myColumn.myArray[2]
            }
        }
    

    and I'm getting this error: "Unable to assign [undefined] to QString"

    EDIT: I've stepped through this in the debugger, and the array is most definitely being created.



  • @mzimmers said in accessing aggregates (QVector of a struct):

    Column {
    id: myColumn
    property var myArray: []
    Component.onCompleted: DataSource.getData().forEach(function(bottle) {
    // template.createObject(this, { text: bottle.name });
    myArray.push(bottle.name)
    }, this)

    you should not modify myArray directly in the function but create a local array then copy its content into myArray

    Column {
            id: myColumn
            property var myArray: []
            Component.onCompleted: {
               var arr = []
               DataSource.getData().forEach(function(bottle) {           
                //myArray.push(bottle.name)
                  arr.push(bottle.name)
            }, this);
          myColumn.myArray = arr;          
    }
    


  • @LeLev that works! Thanks for your patience on this.

    May I ask why my approach didn't work?



  • @mzimmers
    here is an example to illustrate, uncomment one or the other Component.onCompleted, you will observe that when we call
    col.myArr.push("N° " + i) directly, the view is empty at the beginning but myArr actually contains the items

    Window {
        width: 640
        height: 480
        visible: true
    
        Column{
            id:col
            property var myArr : []
    
    // calling myArr.push() directly in the function.
    //   You will need to somehow "refresh" the view, (in this example see the button that resets the repeater model)
            
    //        Component.onCompleted: {
    //            var arr = []
    //            for(var i=0;i<10;i++){
    //                col.myArr.push("N° " + i)
    //            }
    //        }
    //OR ------------------------------------------
    // creating a local array        
            
    //        Component.onCompleted: {
    //            var arr = []
    //            for(var i=0;i<10;i++){
    //                arr.push("N° " + i)
    //            }
    //            col.myArr = arr;
    //        }
    
            //--------------------------------------------------
            Repeater{
                id:rep
                model: col.myArr.length
    
                Text {
                    id: txt
                    text: col.myArr[index]
                }
            }
            //--------------------------------------------------
            Button{ 
                text: 'refresh'
                onClicked:{ rep.model = 0; rep.model = col.myArr.length;  console.log(col.myArr) } // just to reset the repeater
            }
        }
    }
    

    It's great that your solution worked but why not implement something where you can simply write

     Text {
                text: DataSource.getDataByIndex(0).name 
            }
    


  • @LeLev I may have spoken a bit too soon...when I try to apply this from the example to my application, I get the error again.

    Column {
    	id: myColumn
    	property var myArray: []
    	Component.onCompleted: {
    		var arr = []
    		BottleList.getBottleListQv().forEach(function(bottle) {
    			arr.push(bottle.name)
    		}, this);
    		myColumn.myArray = arr;
    	}
    
    	Bottle {
    		cellText: myColumn.myArray[0]//"W7"
    	}
    

    The array element notation seems like it's correct; can you see what I'm doing wrong?

    Regarding writing a function for the name: I would do that, and I still may, but I want to grow this to return several values in the struct: name, position, capacity, fill level, etc. So far, this approach looks better for that.



  • @mzimmers said in accessing aggregates (QVector of a struct):

    I get the error again.

    what error do you get ? Did you read/test my example with all the comments about the arrays, i think the error you get is related to that


Log in to reply