0

Starting from the popular Qt SimpleTreeModel, I want to be able to update the entire tree view with new data. The example only populates the tree view once on start up, it does not update the tree view afterwards.

I have made some edits to the example (treeview is now in a dialog so I can press "PushButton" to update treeview) and when I update the tree view, the top most TreeItems become the child TreeItems for each topmost TreeItem. When I update the treeview in this case, before and after should be the same as it is the same data, I don't see why before and after would be different. The screenshots below better illustrate the problem:

Before Updating

enter image description here

After Updating, you can see below that if I click on a item that is used multiple times, they all highlight, which makes sense as they are all (probably) pointing to the same item (I'm not sure how).

enter image description here

My edits to the SimpleTreeModel are below:

main.cpp

#include "dialog.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    Q_INIT_RESOURCE(simpletreemodel);

    QApplication app(argc, argv);

    Dialog dialog;
    dialog.show();

    return app.exec();
}

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

#include <QFile>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QFile file(":/default.txt");
    file.open(QIODevice::ReadOnly);
    model = new TreeModel(file.readAll());
    file.close();

    ui->treeView->setModel(model);
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::on_pushButton_clicked()
{
    model->redrawAll();
}

treeitem.cpp (exactly the same as example except with new function below)

void TreeItem::removeChildren() {
    m_childItems.clear();
}

treemodel.cpp (exactly the same as example except with new functions below). I am removing all children from rootItem so I can put completely new data on a each update.

TreeModel::TreeModel(const QString &data, QObject *parent)
    : QAbstractItemModel(parent)
{
    QList<QVariant> rootData;
    this->data1 = data;
    rootData << "Title" << "Summary";
    rootItem = new TreeItem(rootData);
    setupModelData(data.split(QString("\n")), rootItem);
}

void TreeModel::redrawAll() {
    rootItem->removeChildren();

    setupModelData(data1.split(QString("\n")), rootItem);

    emit dataChanged(QModelIndex(), QModelIndex());

}

EDIT: I have modified the redrawAll function to below. The result is the same screenshot after updating as the previous TreeModel::redrawAll() function with emit dataChanged(QModelIndex(), QModelIndex()).

void TreeModel::redrawAll() {
//    beginResetModel();
    rootItem->removeChildren();

    QFile file(":/default.txt");
    file.open(QIODevice::ReadOnly);
    QString data = file.readAll();
    setupModelData(data.split(QString("\n")), rootItem);
    file.close();

//    endResetModel();

//    emit dataChanged(QModelIndex(), QModelIndex());

    qDebug() << "TreeModel::redrawAll() " << rowCount() << columnCount();
// the output is TreeModel::redrawAll()  6 2
    QModelIndex topLeft = this->index(0, 0);
    QModelIndex bottomRight   = this->index(rowCount(), columnCount());
    emit dataChanged(topLeft, bottomRight);

}
stretch
  • 211
  • 1
  • 2
  • 10

1 Answers1

1

The dataChanged() signal that you emit is nonsense. Not only is the invalid index range not allowed, but dataChanged() only indicates a change in contents of the data items, not in the structure of the tree. You seem to be changing the structure as well.

Since you seem to be changing the contents the entire model, you should indicate that you've reset the model:

void TreeModel::redrawAll() {
  beginResetModel();
  ...
  endResetModel();
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I have tried your suggestion and it works (before and after is the same), however it closes all the branches of the treeview. In my actual project I am updating many times a second so to expand each row after update is impracticable. In this problem, the structure of each update is the same, only the contents are changing (well in my post, the data should be the same on each update). The range of the dataChanged is from here (I haven't found anything about this in the qt docs) https://stackoverflow.com/questions/29141038/what-does-bottomright-mean-when-using-datachanged-with-a-qtreeview-in-qt – stretch Sep 26 '17 at 14:40
  • If you keep the structure of the model the same, then you need to issue `dataChanged` signals for every branch of the tree that are not leaves, and each of those signals should cover all children in that branch. The two invalid indices won't work - you already know that. – Kuba hasn't forgotten Monica Sep 26 '17 at 17:45
  • I have edited my question with a new `TreeModel::redrawAll() ` function. However `emit dataChanged(topLeft, bottomRight)` gives the same result as `emit dataChanged(QModelIndex(), QModelIndex())`. Actually every topLeft, bottomRight combination gives the same result e.g. `[ (0,0), (1,1) ]; [ (0,0), (0,0) ]; [ (1,1), (1,1) ]; [ (0,0), (6,2) ];` (except [ (0,0), (0,0) ]; [ (1,1), (1,1) ]; takes longer to update than the others?) I'm not sure what I'm doing wrong? – stretch Sep 27 '17 at 00:16