Important: Please read the Qt Code of Conduct -

Gridview dynamic update on C++ model setData() or qml ListModel set()

  • Hi all,

    I'm having problems understanding why this is not working, I just want to have an item in the view dynamically updated when I change the data in the model using the ListModel method set() , I've also used a C++ model and setData() which emits dataChanged() signal but I can't see any refresh though. I'm stucked.

    import QtQuick 2.5
    import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.2
    Dialog {
        id: mydialog
        anchors.centerIn: parent
        width: parent.width / 2
        height: parent.height / 2
        padding: 32
        modal: true
        ListModel {
            id: theModel
            ListElement { number: 0 }
            ListElement { number: 1 }
            ListElement { number: 2 }
            ListElement { number: 3 }
            ListElement { number: 4 }
            ListElement { number: 5 }
            ListElement { number: 6 }
            ListElement { number: 7 }
            ListElement { number: 8 }
            ListElement { number: 9 }
        ColumnLayout {
            anchors.fill: parent
            property int count: 9
            Button {
                Layout.alignment: Qt.AlignTop
                Layout.preferredHeight: 20
                Layout.preferredWidth : 50
                text: qsTr("add")
                onClicked: {
                    console.debug("add element")
                    theModel.append({"number": ++parent.count});
            Button {
                Layout.alignment: Qt.AlignCenter
                Layout.preferredHeight: 20
                Layout.preferredWidth : 50
                text: qsTr("set")
                onClicked: {
                    theModel.set(0, {"number": 12});
            GridView {
                Layout.alignment: Qt.AlignBottom
                id: view
                Layout.preferredHeight: 100
                Layout.preferredWidth : 400
                //anchors.margins: 20
                clip: true
                model: theModel
                cellWidth: 45
                cellHeight: 45
                delegate: numberDelegate
            Component {
                id: numberDelegate
                Label {
                    width: 400
                    height: 40
                    text: index

    follows a second attempt which is more my real case ( I have a custom C++ model ) registered in My.Models 1.0 -> MyModel . It's bit better as I'm able to change the values in the view but the view items are not refreshed until I scroll up or down. Using grid.forceLayout() didn't solve, the only solution I've found is to set grid.model = 0 and reset the model with grid.model = mymodel . I expect this to work without any special trick. here is the code ( I've stripped it lot of lines so maybe the syntax is not correct, hope it's enough ):

    import QtQuick 2.12
    import QtQuick.Controls 2.5
    import QtQuick.Layouts 1.3
    import QtQuick.Controls.Material 2.3
    import My.Models 1.0
    Dialog {
        id: root
        anchors.centerIn: parent
        width: 1000
        height: 700
        padding: 32
        modal: true
        Connections {
            target: MyClass
            // MyClass emit this signal
            onFinishedParsing: {
                // this is an example trying to set all model data to "0.2" , in a real case this data come from MyClass
                for (var i = 0; i < mymodel.rowCount(); i++) {
                    mymodel.setData(mymodel.index(i, 0),"0.2",MyModelModel.Value)
        ColumnLayout {
            anchors.fill: parent
            spacing: 16
           GridView {
                id: grid
                Layout.fillHeight: true
                Layout.fillWidth: true
                contentWidth: width
                cellWidth: width / 4
                cellHeight: 80
                clip: true
                model: MyModel {
                    id: mymodel
                delegate: Label {
                    text: model.value

    the setData method in MyModel is:

    bool SimplsModel::setData(const QModelIndex &index, const QVariant &value,
                              int role) {
      if (index.isValid() && role == SimplsModel::Roles::Value) {
        m_rowData[index.row()].value = value.toFloat();
        emit dataChanged(index, index, {SimplsModel::Roles::Value});
        return true;
      return false;

    I'm really stucked , can't see what's wrong. any help would be really appreciated. thanks.

  • Here is my code which use the QAbstractListModel: TestModel

    When change the data, try call beginResetModel and endResetModel.

    void TestModel::addDao(const QString &name, int age)
        m_datas.append(Dao(name, age));

  • When change the data, try call beginResetModel and endResetModel.

    Don't (I wouldn't anyhow) do that, that's a big hammer. I do use that but only for a whole set of data.
    For an simple append ~not really right.

    setData & emit dataChanged is correct.

    When reimplementing the setData() function, this signal must be emitted explicitly.

    I emit that the whole row changed with mine (see the first 2 args below), but I'm not sure even this is fully optimal. It does work for me - just working is enough for me atm and I'd like to get time to experiment restricting to a unique.

      emit QAbstractTableModel::dataChanged(QAbstractTableModel::index(intOfIter, 0), QAbstractTableModel::index(intOfIter, columnCount()-1), QVector<int>() << role);

    I'm still getting my head around trying to get setData actually working from QML side with custom roles, from Table view but this works from Cpp backend, I'm trying to get a complex control sorted that can handle updates with dynamic delegates from QML.

    Hopefully this is just enough to get you across the line and moving again too.

  • @qyvlik

    beginResetModel() / endResetModel()

    works but actually is a lot of overhead in in setData, I think it's ok if I want to upadate the whole model data in one shot , thanks


    I've tried this but it didn't solve, as before it do set the data but the view doesn't refresh de delagates, maybe I didn't realize how to apply it for a QAbstractListModel:

    emit QAbstractListModel::dataChanged(QAbstractListModel::index(index.row()), QAbstractListModel::index(index.row()), QVector<int>() << SimplsModel::Roles::Value); 
    emit QAbstractListModel::dataChanged(QAbstractListModel::index(index.row()), QAbstractListModel::index(index.row()), QVector<int>() << Qt::DisplayRole);

    Strange that we have to fight to make this work, I can't find code examples about people achieving this, Am I doing something unusual ? ( I wander )


Log in to reply