I have a QML ListModel like follows:
ListModel { id: myListModel ListElement {myId: "1", myValue = "12"} ListElement {myId: "2", myValue = "0"} ... ListElement {myId: "21", myValue = "123"} }
Then I have some simple QML labels like follows:
Label { id: myLabel1 property int labelInt: 1 text: myListModel.get().myValue; //Here is my problem! } Label { id: myLabel2 property int labelInt: 22 text: myListModel.get().myValue; //Here is my problem! }
My problem is to fill that brackets in myListMode.get().myValue. In fact I need a condition: if myListModel has some myId that equals my current labelInt, then return me the corresponding myId, otherwise leave empty space:
I tried with:
myListModel.get(myListModel.get(myId = labelInt).myId).myValue;
but I am not sure It’s the proper way.
Can you help me? Thank you
Advertisement
Answer
If you speed is your desire, you should map you entries to the myId
.
In QML you can do this with a combination of a Instantitator
and a JSObject
.
property var tracker: ({}) Instantiator { model: tm delegate: QtObject { id: instDummy property QtObject modelData: model property string __oldID property string myID: model.myID onMyIDChanged: { if (myID && __oldID !== myID) { delete tracker[__oldID] __oldID = myID tracker[__oldID] = instDummy console.log('changed', Object.keys(tracker)) } } Component.onCompleted: { __oldID = myID } Component.onDestruction: { console.log(__oldID, modelData.myID, delete tracker[__oldID]) console.log('removed', Object.keys(tracker)) } } }
Explanation:
The Instantiator
creates a QtObject
for each entry in the model. This QtObject
stores a reference to the model data of the entry. The two properties myID
and __oldID
are used to keep the Map (JSObject) tracker
up to date.
myID
is bound to the model.myID
so, whenever this would change it would trigger the signal on myID
changed. Now I need to change the key in the map from the old value to the new value. Therefore I delete the entry with the key __oldID
, then I update __oldID
to the new myID
and add the object back into the map, with the new key.
I don’t want __oldID
to be bound, therefore I assign it in Component.onCompleted
.
When the entry is removed, I remove the object and the reference from the Map
as well, so I keep my map as clean as possible.
When a new entry is added, the Instantiator
will automatically add a new QtObject
for this.
Now you can query your myID
in O(1)
with tracker[myID]
. The Instantiator
takes care that all changes will be tracked. It only changes, when there is a change to the model in the specific row.
Note that this method will take a toll on your memory, as it will basically duplicate your model in the hashmap.
To avoid this, you might implement a ProxyModel
in C++, e.g. based on the QIdentityProxyModel
to which you add a mapping of the myID
and the actuall model index. Handle the dataChanged
-signal to keep that map up-to-date.
PS: I expect that at least the myID
is unique. Otherwise like this, you might lose some references. Use buckets then, to keep multiple entries in the map for shared myID
‘s