2

I have a QML TreeView that gets data through a QStandardItemModel. When the application is running, I press a button which adds a new entry. I know the data is changing, but the QML TreeView is not updating. I've also tried beginResetModel() and endResetModel(). The data is correctly displayed in the TreeView upon loading the application, but the TreeView does not change when modifying the data in the model.

treeviewmodel.cpp

#include <QDebug>
#include <QStandardItemModel>
#include "treeviewmodel.h"

TreeViewModel::TreeViewModel(QObject *parent) :
    QStandardItemModel(parent)
{
    m_roleNameMapping[TreeViewModel_Role_Name] = "name_role";

    QStandardItem* entry;
    entry = new QStandardItem(QString("my_entry"));
    entry->setData("abc", TreeViewModel_Role_Name);

    auto childEntry = new QStandardItem( "my_child_entry" );
    childEntry->setData( "def",TreeViewModel_Role_Name);
    entry->appendRow(childEntry);
    appendRow( entry );

}
TreeViewModel& TreeViewModel::Instance()
{
    static TreeViewModel instance; //Guaranteed to be destroyed
    return instance;
}
void TreeViewModel::addEntry()
{
    qDebug () << "Adding entry...";

    QStandardItem* entry;
    entry = new QStandardItem(QString("my_entry"));
    entry->setData("Second Entry", TreeViewModel_Role_Name);
    auto childEntry = new QStandardItem( "my_child_entry" );
    childEntry->setData( "Second Entry Child",TreeViewModel_Role_Name);
    entry->appendRow(childEntry);
    appendRow( entry );
    qDebug () << rowCount(); //Increases everytime I call the function
                             //Data is being added
}
QHash<int, QByteArray> TreeViewModel::roleNames() const
{
    return m_roleNameMapping;
}

main.qml

import treeModel 1.0
...
MyTreeModel {
    id: theModel
}

//Left Tree View
Rectangle {
    id: leftView
    Layout.minimumWidth: 50
    width: 200
    //Layout.fillWidth: true
    color: "white"
    TreeView {
        id: treeView
        anchors.fill: parent
        model: theModel
        TableViewColumn {
            role: "name_role"
            title: "Name"
        }
        TableViewColumn {
            role: "description_role"
            title: "Description"
        }
    }
}

ToolButton {
    iconSource: "lock.png"
    onClicked: {
    treeviewmodel.addEntry()
    }
}

main.cpp

QQmlContext* treeViewModelCtx = engine.rootContext();
treeViewModelCtx->setContextProperty("treeviewmodel", &TreeViewModel::Instance());

//Register types
qmlRegisterType<TreeViewModel>("treeModel", 1, 0, "MyTreeModel" );
  • As a temporary workaround, `treeviewmodel = treeviewmodel` after the call to `addEntry` maybe works. – skypjack Nov 04 '16 at 23:44
  • I suspect you have to emit [`dataChanged`](http://doc.qt.io/qt-5/qabstractitemmodel.html#dataChanged) within `addEntry` to notify the view that it has to reload data. Does it work emitting that signal? – skypjack Nov 04 '16 at 23:50
  • The call to `QStandardItemModel::appendRow` *should* result in a `QAbstractItemModel::rowsInserted` signal being emitted. Try connecting that signal to a dummy slot to verify it is being emitted. – G.M. Nov 05 '16 at 08:20
  • @skypjack `treeviewmodel = treeviewmodel` does not work and `dataChanged()` requires QModelIndex as parameters, not sure how to implement that. – Francisco Hernandez Nov 05 '16 at 20:58
  • TreeView is just broken and Qt does not care about it. It does not react to endInsertRows, endRemoveRows and the accompanied signals. It does also not react to signals like layoutChanged... – IceFire May 10 '21 at 06:25

1 Answers1

1

I hope this example helps. Unfortunately, I don't have your whole code to see where the problem is.

Maybe the keys are the data and roleNames methods.

In this example, we also have a button called addButton to add new items.

main.cpp

#include "animalmodel.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>
#include <qqml.h>

int main(int argc, char ** argv)
{
    QGuiApplication app(argc, argv);

    AnimalModel model;
    model.addAnimal("Wolf", "Medium");
    model.addAnimal("Polar bear", "Large");
    model.addAnimal("Quoll", "Small");

    QQmlApplicationEngine engine;

    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("myModel", &model);

    engine.load(QUrl(QStringLiteral("qrc:/view.qml")));

    return app.exec();
}

animalmodel.h

#ifndef ANIMALMODEL_H
#define ANIMALMODEL_H

#include <QStandardItemModel>

class AnimalModel : public QStandardItemModel
{
    Q_OBJECT
public:
    enum AnimalRoles {
        TypeRole = Qt::UserRole + 1,
        SizeRole
    };

    AnimalModel(QObject *parent = 0);

    Q_INVOKABLE void addAnimal(const QString &type, const QString &size);

    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

protected:
    QHash<int, QByteArray> roleNames() const;
};

#endif // ANIMALMODEL_H

animalmodel.cpp

#include "animalmodel.h"

AnimalModel::AnimalModel(QObject *parent)
    : QStandardItemModel(parent)
{

}

void AnimalModel::addAnimal(const QString &type, const QString &size)
{
    QStandardItem* entry = new QStandardItem();
    entry->setData(type, TypeRole);

    auto childEntry = new QStandardItem();
    childEntry->setData(size, SizeRole);
    entry->appendRow(childEntry);

    appendRow( entry );
}

QVariant AnimalModel::data(const QModelIndex & index, int role) const {
    QStandardItem *myitem = itemFromIndex(index);

    if (role == TypeRole)
        return myitem->data(TypeRole);
    else if (role == SizeRole) {
        if (myitem->child(0) != 0)
        {
            return myitem->child(0)->data(SizeRole);
        }
    }

    return QVariant();
}

QHash<int, QByteArray> AnimalModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[TypeRole] = "type";
    roles[SizeRole] = "size";
    return roles;
}
Tarod
  • 6,732
  • 5
  • 44
  • 50
  • I was registering the qml type by doing `qmlRegisterType("treeModel", 1, 0, "MyTreeModel" );` which would load the initial state of the view, but it would not refresh. Your approach works, thank you. However, when trying to select items on the `TreeView` is kind of unresponsive, have you experienced that issue before? – Francisco Hernandez Nov 07 '16 at 18:31
  • It's very strange, if I click on a row in the `TreeView`, the row does not get selected. I think it's this bug: https://bugreports.qt.io/browse/QTBUG-47243. By the way, the link you posted is broken. Thanks for the help! – Francisco Hernandez Nov 08 '16 at 00:35
  • (fixed comment) Sorry! I didn't realize that line of code in your main.cpp. Yes, that was the issue. Good job :) About the TreeViews, I don't remember any problem with them. Qt [has](http://doc.qt.io/qt-5/qtquickcontrols-filesystembrowser-example.html) a good example with TreeView. Maybe it helps you to see if you get the same issue in that example. – Tarod Nov 08 '16 at 06:14
  • I do have the same issue with that example, I'll contact Qt for support. Thanks! – Francisco Hernandez Nov 08 '16 at 18:12