How to read properties for the currenetly selected item in a ListView
-
I want to be able to click on an elemnt in a ListView in order to select it and show a detail view for it.
This is what I've tried:
ListView { id: list width: 180; height: 200 model: myModel // QAbstractListModel onCurrentItemChanged: { // how to get the current item? var title1 = myModel[currentIndex].title; // not working var title2 = myModel.data(currentIndex).title; // not working var title3 = currentItem.data.title; // not working var title4 = currentItem.get(currentIndex).title; // not working } delegate: Component { Item { width: 200 height: 30 Text { id: text text: title } MouseArea { anchors.fill: parent onClicked: { list.currentIndex = index; } } } } }
-
Duh! I knew my focus was wrong. Doing it inside MouseArea's onClicked is a lot easier!
Side note: myModel.get() doesn't seem to work. I assume this is implemented for ListModel only, not AbstractItemModel.
-
If anyone has an example of reading properties from the currentItem inside onCurrentItemChanged that would be nice for later reference. Even though I've solved my case by moving work to onClicked.
I'll mark the question as solved after a while.
-
You can do this by multiple ways.
Since you have access to the currentItem you could expose its context properties (that's how it can access to the model roles) as normal properties in your delegate:
property string title: model.title
, then you could doonCurrentItemChanged: { var title = currentItem.title; }
. This has the inconvenient that the item can possibly be destroyed (if it gets scrolled out of the viewport for example) and then you won't be able to reference it. Maybe there's a special case where currentItem don't get destroyed but I don't know, it's not really documented.Another way is to access the context properties of the current item yourself without exposing them in the delegate. Sadly it's not possible from QML out of the box. One could write an attached object in c++ but this is fairly advanced. The API could be of the form:
onCurrentItemChanged: { var title = currentItem.Context.title; }
. This has the same limitation as above.Like Leonardo said, you could also access it from the model directly with the currentIndex. The model however has to provide an invokable method to expose this, like the
get()
method inListModel
. It's not standard inQAbstractItemModel
so models have to implement that themselves. If you can modify your model, you can add a method like that, it's pretty straightforward.A last solution would be a generic way to access data from a model in QML, like I said earlier there's no standardized way to get data out a of a model from QML but all
QAbstractItemModel
has to implementdata()
. The problem is that it's not callable from QML. I wrote a library to help with that : https://github.com/oKcerG/QmlModelHelper
Just include the .pri in your .pro, in your qml file addimport ModelHelper 0.1
and then you could use it like that :onCurrentIndexChanged: { var title = myModel.ModelHelper.get(currentIndex).title; }
Here's the WIP readme : https://gist.github.com/oKcerG/eeea734bdacc51b3ae58650de5f05943 -
@tskardal , you can write a get function in the QAbstractListModel as below
//declaration Q_INVOKABLE QVariantMap get(int row); //definition QVariantMap get(int row) { QHash<int,QByteArray> names = roleNames(); QHashIterator<int, QByteArray> i(names); QVariantMap res; while (i.hasNext()) { i.next(); QModelIndex idx = index(row, 0); QVariant data = idx.data(i.key()); res[i.value()] = data; //cout << i.key() << ": " << i.value() << endl; } return res; }
and in the QML you can use it as below
myModel.get(1).title //where 1 is an valid index.
-
@tskardal Hey, I know this is an old topic, but I was directed here from Google when looking for a solution for this exact problem. Luckily I found this SO question from 2015 that has a built-in elegant solution. It has to do with using DelegateModel to encapsulate the QAbstractListModel and let the user get any item at a certain index.
In OP's case, the solution will look like this:
import QtQml.Models 2.15 //need this for DelegateModel ListView { id: list width: 180; height: 200 model: DelegateModel{ id:myDelegateModel model: myModel // QAbstractListModel delegate: Component { Item { width: 200 height: 30 Text { id: text text: title } MouseArea { anchors.fill: parent onClicked: { list.currentIndex = index; } } } } } onCurrentItemChanged: { var currentModelItem = myDelegateModel.items.get(list.currentIndex).model console.log("Current Item title is: " + currentModelItem.title) } }
There are more current answers that to my humble opinion are far more convoluted than this solution.