0

I'm trying to implement a callback function on my QML ListModel to do some operations when the data inside the ListModel changes. Apparently, it's impossible to create on...Changed handlers for individual user-defined properties in a ListModel. So, I'm trying to use the onDataChanged handler available to ListModel.

ListModel {
    id: model

    onDataChanged: {
        console.warn("onDataChanged: "+get(topLeft).val + " vs. " + get(bottomRight).val)
    }
}

However, onDataChanged only ever seems to reference the very first element in the ListModel. That is to say, topLeft and bottomRight always point to the first element, even when I manipulate an element down the list.

What I need here is a reliable handler that accurately reflects the correct row in the ListModel when it fires off.

user1765354
  • 347
  • 1
  • 5
  • 21
  • If you use a [generic object model](http://stackoverflow.com/questions/35160909/how-to-create-a-generic-object-model-for-use-in-qml/35161903#35161903) you can then use regular properties with individual change notifications. – dtech Jan 31 '17 at 19:08
  • Not possible due to constraints of project. Why would onDataChanged return the very first row when I manipulate a different row? Am I just using these parameters incorrectly? – user1765354 Jan 31 '17 at 19:11
  • The arguments of `QAbstractItemModel::dataChanged()` are `QModelIndex`, i.e. objects of a class type. You are passing these to functions expecting integers, the JavaScript environment will likely do one of its magic type conversions. Using a ListModel for data that changes is odd, usually indicates that a proper custom model would be better. – Kevin Krammer Feb 01 '17 at 09:29

1 Answers1

0

When I change the data in a ListModel everything seems right. Try this example:

Window {
    id: mainWindow
    visible: true
    width: 1200
    height: 800

    ListModel {
        id: lm
        ListElement { test: 0 }
        ListElement { test: 0 }
        ListElement { test: 0 }
        ListElement { test: 0 }
        ListElement { test: 0 }

        onDataChanged: console.log('Data Changed', topLeft.row, get(topLeft.row).test, data(topLeft, roles[0]))
    }

    ListView {
        width: 200
        height: 800
        model: lm
        delegate: Button {
            text: model.test
            onClicked: model.test++
        }
    }
}

The QML-get-function expects a Integer that indicates the index, which corresponds to the QModelIndex.row. Mark that in QML you have the row as property, so .row() will fail.

What you can alternatively use is the data(index, role)-method. This takes a QModelIndex as index, and the role as Integer. This is fortunate, as I know no non-hacky way to retrive the mapping from the integer-typed roles provided by the signal, into the roleNames usually used in QML.