Solved updating elements in a repeater?
-
typedef QVector<Bottle> Bottles;
If
Bottle
is derived fromQObject
you can't keep it directly in a vector (can't copy the objects). You need to keepBottle *
there. -
@kshegunov ah. OK, thanks for that. I'll look into making that change, and will report back.
-
I've changed my QVector to pointers (seems to be working).
I think I see why my example is so confusing -- in my Bottle Repeater, I'm using a QML ListModel. This ListModel only contains UI-specific information (position, size). Additional informationmust come from an object (ReagentManager) that is exposed via a call to setContextProperty().
So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?
Thanks...
-
@mzimmers said in updating elements in a repeater?:
So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?
Why do you need the
ListModel
is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater. -
@kshegunov said in updating elements in a repeater?:
Why do you need the
ListModel
is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater.I'm using the list model for UI-specific information:
ListModel { id: bottleModel ListElement { // position 1 x: 400 y: 17 height: 75 width: 75 } ...
I could probably put this data in arrays in QML. As I mentioned, I'd prefer not to put it into my C++ as it's purely UI data.
From my definition of the ReagentManager class:
class ReagentManager : public QObject { Q_OBJECT public: explicit ReagentManager(QObject *parent = nullptr); Bottles m_bottleList; Q_PROPERTY(Bottles bottleList MEMBER m_bottleList) ...
And in my QML:
function updateBottles() { var modelSize = bottleModel.count var i var volume for (i = 0; i < modelSize; ++i) { volume = reagentManager.bottleList[i].volume ...
I'm getting an error "TypeError: Cannot read property '0' of undefined." Is my syntax wrong, or am I still not understanding how to access the property?
Thanks...
EDIT: looking at the QML Debugger Console, I see this message:
QMetaProperty::read: Unable to handle unregistered datatype 'Bottles' for property 'ReagentManager::bottleList'
-
@mzimmers said in updating elements in a repeater?:
I could probably put this data in arrays in QML. As I mentioned, I'd prefer not to put it into my C++ as it's purely UI data.
You already have this data in the c++, you feed it to the JS engine as far as I can see. I'd just tie the cpp backend to the UI stuff and not mess with any intermediate stuff, much less using explicit JS code.
Basically like this:
Column { Repeater { model: reagentManager.bottleList //< This being a property that holds the list of bottles Bottle { cellX: modelData.x cellY: modelData.y //< Or use some other value, or nothing, however you decide to do it ... volume: modelData.volume //< This binds to the property of the QObject, so when the C++ changes value this updates ... } ... }
@mzimmers said in updating elements in a repeater?:
I'm getting an error "TypeError: Cannot read property '0' of undefined." Is my syntax wrong, or am I still not understanding how to access the property?
Thanks...
EDIT: looking at the QML Debugger Console, I see this message:From the method:
https://doc.qt.io/qt-5/qqmllistproperty.html
or
you returnQList<QObject *>
or
you return aQVariantList() << bottle1 << bottle2
... different possibilities.
-
I've changed my typedef from a QVector to a QList:
typedef QList<Bottle *> Bottles;
My C++ looks like this (stripped down) now:
struct Bottle : public QObject { Q_OBJECT Q_PROPERTY(quint32 volume MEMBER m_volume) public: quint32 m_volume; // amount in bottle (in uL) signals: void volumeChanged(quint32 m_volume); }; typedef QList<Bottle *> Bottles; class ReagentManager : public QObject { Q_OBJECT private: Bottles m_bottleList; public: Q_INVOKABLE Bottles bottleList() { return m_bottleList; } void bottleListChanged(); };
And this line in QML:
volume = reagentManager.bottleList[i].volume
Now produces this error:
qrc:/qml/Rack.qml:194: TypeError: Cannot read property 'volume' of undefined
So...I've kicked the can a little further down the street, but I'm not home yet. It seems that the QML can now access the QList (agree?), but not its properties. Do I need a getter for this? I thought the idea of getting the properties working properly was to eliminate the need for the getters/setters.
-
@mzimmers said in updating elements in a repeater?:
volume = reagentManager.bottleList[i].volume
bottleList is a function but you are accessing like an array
volume = reagentManager.bottleList()[i]
-
@LeLev said in updating elements in a repeater?:
@mzimmers said in updating elements in a repeater?:
volume = reagentManager.bottleList[i].volume
bottleList is a function but you are accessing like an array
volume = reagentManager.bottleList()[i]
Thanks...I thought this would work:
volume = reagentManager.bottleList()[i].volume
But I get this error:
Error: Unknown method return type: Bottles
This goes back to what kshegunov was talking about earlier, but I thought I'd fixed this by changing from a QVector to a QList:
typedef QList<Bottle *> Bottles; class ReagentManager : public QObject { Q_OBJECT public: Q_INVOKABLE Bottles bottleList() { return m_bottleList; }
I'm still missing something...
-
@mzimmers said in updating elements in a repeater?:
I'm still missing something...
i would return a QVariantList to qml instead of the QList<Bottle *>
-
@LeLev OK, but...how do I do that? I can't just cast it. Do I have to change my Bottles typedef?
Thanks...
-
Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }
-
this is not directly related but
@mzimmers said in updating elements in a repeater?:onVisibleChanged: {
if (visible) {
reagentManager.updateBottleList()
rack.updateBottles()
}
}are you calling this in your Repeater delegate ? If yes, then i believe you will call this multiple times unnecessarily, one way to verify it in qml is putting a console.log() after or before this call to see how meny time this is called
-
@LeLev said in updating elements in a repeater?:
Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }
Well, bless my buttons...that works! But why is bottleList() declared as returning a QVariant, and not a QVariantList?
Regarding your question: the onVisibleChanged isn't in the repeater; it's in the parent Rectangle. This was my way of ensuring that the C++ data in ReagentManager updates itself whenever the view is activated.
-
@mzimmers said in updating elements in a repeater?:
Well, bless my buttons...that works!
Nice :)
@mzimmers said in updating elements in a repeater?:
But why is bottleList() declared as returning a QVariant, and not a QVariantList?
I don't have a technical explanation for that really, im used to do that since i saw it somewhere in the docs. But i guess you could return a QVariantList directly. It will be converted to javascript array as explained here https://doc.qt.io/qt-5/qtqml-cppintegration-data.html