24

I'm trying to access a role from a ListView in QML. Essentially, I have this in my QML:

ListView {
    id: myId
    model: myModel
    delegate: Item {
        Text {
            text: model.text
        }
        Text {
            text: model.moreText
        }
    }
}

myModel is a QAbstractListModel implementation. The QML portion of this is a reusable component, so the model could have any number of different roles with various data types. What I would like to do is bind to the value of a given role of the currentItem property of the ListView. In other words, I'd like to have some other Component on the page that could bind a property to the currently selected item in the ListView as follows:

Text {
    text: myId.currentItem.text // Or myId.currentItem.model.text (or something similar)
}

Please keep in mind that I need this generically available, as I'll be doing this a lot for a number of model types and I'm trying not to write that kind of custom code for each model and ListView.

It seems like it should be simple to access a property of the currently selected item, but as far as I can tell it is not possible. The problem is complicated further by the fact that models appear to be treated differently when there is only one role. By this I mean that sometimes you access your roles via model.roleName whereas when there is only one role you use modelData.

If anybody has any suggestions, I would truly appreciate it. Thanks so much!

EDIT

I found this:

http://comments.gmane.org/gmane.comp.lib.qt.qml/1778

However, this doesn't appear to work for me. I'm getting type errors when I try to use the data in my QML scripts, and there is no type casting available so I'm not sure what to do. Any suggestions are welcome!

Thanks!

Jack

Jack Benson
  • 645
  • 2
  • 6
  • 8

3 Answers3

32

The code at http://comments.gmane.org/gmane.comp.lib.qt.qml/1778 should work, although I do see errors if the property is named 'data'; it looks like it is overriding some existing built-in property. Renaming it to 'myData' seems to work:

ListView {
    id: myId
    model: myModel
    delegate: Item {
        property variant myData: model
        Text {
            text: model.text
        }
        Text {
            text: model.moreText
        }    
    }
}

Text { text: myId.currentItem.myData.text }

(The myId.currentItem.text code in the original post didn't work because this was trying to refer to a text property within your delegate, which didn't exist.)

In regards to referring to model vs modelData within the delegate, the difference depends on the type of the model, rather than the number of roles in the model. If the model is a string list or object list, modelData is used to refer to the individual string or object from within a delegate (since string lists and object lists do not have any roles). For all other models, including the QML ListModel and the Qt C++ QAbstractItemModel, model.role can be used to refer to a role within a delegate.

blam
  • 1,125
  • 9
  • 5
  • Thanks so much for your response! Hmm... I thought tried this exhaustively, but there may be some nuance I've missed. It's nice to know it is working for somebody though! I'll give this solution a go again and see if that does the trick. I appreciate the clarification between model.role and modelData. I'll let you know how things turn out. Thanks again! – Jack Benson Mar 09 '11 at 19:59
  • 1
    Looks like it does work. Not sure what I had been missing before. Either way, this solution took hours to find so hopefully now that it's on StackOverflow other people will be able to find it quickly. Thanks again! – Jack Benson Mar 10 '11 at 12:14
  • Is there any way to abstract over the different model types ? I'm asking because I'd like to handle a QML ListModel during testing and an object list in the C++ application using the same QML code. – ssc Aug 29 '13 at 11:18
  • Any idea on getting this same approach working with a ComboBox? There is no `currentItem`... – feedc0de Jul 19 '17 at 15:19
  • Nice. I didn't have to alias the "model" as such, but adding property properties to the ListView delegate allowed me to query the values from eg "onCurrentIndexChanged" handler. – Svend Dec 19 '18 at 09:52
5

You could alternatively access the model directly, with something like

Text { text: myModel[myId.currentIndex].text }
Henry Haverinen
  • 158
  • 1
  • 2
3

You can access a ListElement of ListModel using get() function.

Text { text: myModel.get(myId.currentIndex).text }
Nikhil Augustine
  • 187
  • 2
  • 12
  • Could you please elaborate more your answer adding a little more description about the solution you provide? – abarisone Aug 30 '16 at 09:14
  • 1
    @abarisone myModel is the Model which you will provide to the ListView and myId is the listView and text is is a role. For example `ListModel { id: myModel ListElement { text: "Apple" cost: 2.45 } ListElement { text: "Orange" cost: 3.25 } ListElement { text: "Banana" cost: 1.95 } } ListView { id: myId anchors.fill: parent model: myModel delegate: Text { text: text } }` – Nikhil Augustine Aug 31 '16 at 06:38
  • Is this supposed to work even if the model is defined in c++? Because I can't seem to make it work. It says that property get is not defined. – Savvas Parastatidis Jun 21 '17 at 19:19
  • @Savvas What is the type of your C++ model? – Nikhil Augustine Jun 23 '17 at 16:29
  • It's a QAbstractList stored in an SQL db. – Savvas Parastatidis Jun 25 '17 at 12:19
  • `get()` is a ListModel method. I haven't tested this solution with QAbstractList. You may have to use `QAbstractItemModel::roleNames()` in some way. Check [QAbstractItemModel Class](http://doc.qt.io/qt-5/qabstractitemmodel.html#public-functions) – Nikhil Augustine Jun 27 '17 at 12:26
  • I thing, that if you have own C++ model, you must create own funciton get - in model. I have same problem... – exo Aug 01 '18 at 08:17