Search code examples
qtmodel-view-controllerqtableviewqstandarditemmodel

Issue with QTableView and QStandardItemModel


I am facing strange thing with dynamically adding items to my QStandardItemModel and showing them with QTableView. If the time between events is long enough (like 50 ms) then the view is scrollable, but in case of faster event (10 ms) the view always scrolls down and doesn't allow me to do anything.

So here is the simple code snippet:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#include <QMainWindow>
#include <QTimer>
#include <QTableView>
#include <QStandardItemModel>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QTimer dataTimer;

    QStandardItemModel *model;
    QTableView *view;

public slots:
    void insertData();
};

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>

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

    view = new QTableView(this);
    this->setCentralWidget(view);

    model = new QStandardItemModel(this);
    model->setColumnCount(1);
    view->setModel(model);

    QObject::connect(&dataTimer, &QTimer::timeout, this, &MainWindow::insertData);
    dataTimer.start(10); // 50 here gives correct behaviour while 10 does not
}

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

void MainWindow::insertData()
{
    QList<QStandardItem *> items;
    items.append(new QStandardItem(QTime::currentTime().toString("hh:mm:ss.zzz")));

    model->insertRow(0, items);
    if (model->rowCount() > 20){
        model->removeRow(model->rowCount()-1);
    }
}

dataTimer.start(50) works fine, while dataTimer.start(10) brakes behavior. It is for my laptop and maybe for someone else the numbers will be different but I think logic is clear.

I was thinking that it is kind of too fast and some methods like beginInsertRows() doesn't work well. But that is for custom models usually and here it is just a standard one.

Can someone tell me why that happens? Thank you


Solution

  • 10 ms timer in a GUI thread to affect GUI elements is a bad idea itself. For example, in Windows 10 ms timeout is unattainable by standard means. Does your user really need to see updates of some table data more than 1 time per second? What does he really need? Based on this, you should determine an optimization method.

    Then you could choose:

    1. Decrease timeout of the timer and affect several rows on each event. Seems you have to decrease timeout of the GUI timer in anyway.
    2. Reserve the required number of rows periodically in advance, for example by model->setRowCount(n);
    3. Temporarily disable table refresh by setUpdatesEnabled() method:

      setUpdatesEnabled(false);
      bigVisualChanges();
      setUpdatesEnabled(true);

    4. Sublass one of the Qt model classes and reimplement insertRows() or something more.

    Read
    Fetch More Example.
    Qt Model/View Programming.