Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QML TableView access model properties from delegate

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!

like image 386
Pablote Avatar asked Apr 04 '14 23:04

Pablote


3 Answers

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"
}
like image 190
leemes Avatar answered Oct 25 '22 00:10

leemes


I think it's pretty easy if you read the source code of TableViewItemDelegateLoader.qml (it is a private code in qtquickcontrol)
To access any role you use use : model[your_role_name] .

For exp: model["comment"]

like image 5
Ngọc Tân Đỗ Avatar answered Oct 25 '22 02:10

Ngọc Tân Đỗ


Faced with same problem today, this is result of my investigations (Qt 5.2.x)

If you have hard limit to TableView, there is only one correct solution - use model.get(styleData.row)["roleForStyling"] as @leemes wrote. But it will very slow if you have big amount of data in model and using, for example, proxy model for sorting/filtering.

Direct solution from @leemes answer is great, but in general case not be working, because in TableView any Item wrapped in Loader and therefore independent from parent and other items:

  • When some item is created (where you want to change text style) another element (from which to receive identity) cannot yet be created
  • You may not have "parent" on item creation (i.e. binding will be broken)

In my case, the best solution for deep customise was creation of the simple wrapper for ListView. In this case you have access for complete row data in delegate without the overhead. Highlights for making component ("My own ListView as table"):

  • Create standalone header (Rectangle or Item) - do not use header form ListView.This make it fixed for any amount of data.
  • Wrap ListView to ScrollView (if you need scrollbars)
  • Use Clip: true property in list for make correct
  • Set style for highlight and set highlightFollowsCurrentItem:true in ListView

As bonus in future this may be used for make "TreeTable" :)

like image 3
ShaKeSPeaR Avatar answered Oct 25 '22 02:10

ShaKeSPeaR