QML TableView access model properties from delegate

Pablote picture Pablote · Apr 5, 2014 · Viewed 13.8k times · Source

I have a TableView for which I've defined my own itemDelegate. Now, from within this delegate I can access the value for the column using styleData.value, but I'd also need to access the other properties in this same item but I can't find how to.

I need this, because the text styling needs to change depending on some other property of the item model.

Any ideas? thanks!

Answer

leemes picture leemes · Apr 8, 2014

There is some documentation missing. Within the item delegate you can access the following (taken from the source code of TreeView.qml):

  • styleData (see documentation)
  • model (currently not documented)
  • modelData (currently not documented, not sure about this but I guess it's similar to ListView)

(By the way, what's also missing in the documentation but which is useful is styleData.role. Also, the documentation of the other delegates lacks some available properties too; the best is to peek into the source code of the QML file and have a look for the Loader element which instantiates your delegate. As a plus you learn how that creepy stuff works. ;))

With model and the row/column information you can then navigate to the item data. This code depends on the type of model.

If you're using QML's ListModel, then you can use model.get: model.get(styleData.row)[styleData.role] should then work (untested since I use it rarely, please give feedback).

If you're using a C++ QAbstractItemModel or friends, the best is to add a slot to the model class which takes just the row and role name, since that's the information the TableView works with (nor with role numbers nor with columns...).

However in both cases you shouldn't use the expression in a property binding! The notification system will not work since you don't use the property system for accessing the data. According to your question, I guess you wanted to use it in a expression with binding. I don't know how to properly listen to changes in the model manually.

An alternative approach is to access the other items of the row and provide a property there. Some hints:

  • From within one item, you can access other items of the same row by walking the object tree up twice (first to the Loader which instantiates your component, then to the actual row) and then down twice (first to the particular child object which is a Loader, then its instantiated item). You need to know the column number you want to access (not the role name), I assume you want to access the first column (index 0):

    parent.parent.children[0].item
    
  • You can provide the model data using a property in each item. Assuming a simple Text element this might be:

    Text {
        property variant value: styleData.value // <-- Here you make it available
    
        // your other stuff
    }
    

Putting them together could look like the following. In this example I assume the first row contains an integer, and if it is zero, the second column should be red.

// (within TableView)
itemDelegate: Text {
    property variant value: styleData.value
    text: styleData.value
    color: (styleData.column == 1 && parent.parent.children[0].item.value === 0)
            "red" : "black"
}