Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTreeview and refreshing the model freezes the GUI momentarily.
Forum Updated to NodeBB v4.3 + New Features

QTreeview and refreshing the model freezes the GUI momentarily.

Scheduled Pinned Locked Moved General and Desktop
3 Posts 2 Posters 2.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    sledgehammer_999
    wrote on last edited by
    #1

    I have been trying to help an open source project to fix a particular problem. This project uses a custom treemodel derived from qabstractitemmodel and a custom delegate derived from qitemdelegate. The model has an internal timer which when it expires it fetches the updated values for each cell and emits a dataChanged() signal which contains the whole model. The model usually has 22 columns enabled. This works very well if the rows are few, but when they get above 200 the GUI freezes for almost a second when the timer expires. I initially thought that the retrieval of the updated values was the bottleneck, but with further tests it seems the freeze is caused by the repainting of the treeview.

    I managed to make a small example project. I just output rand() numbers so to be sure that the retrieval of the values isn't the bottleneck. Just click-drag the scrollbar up and down and eventually you will notice the freeze.
    Do you have any idea how to solve this? Any alternative way of updating the model?

    main.cpp
    @#include <QApplication>
    #include "mainwindow.h"

    #include <cstdlib>
    #include <ctime>
    int main(int argc, char *argv[])
    {
    srand(time(NULL));
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
    } @

    mainwindow.h
    @#ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QStandardItemModel>
    #include <QTimer>
    #include <QTreeView>

    class TModel : public QStandardItemModel
    {
    Q_OBJECT

    public:
    TModel( int rows, int columns, QObject * parent = 0 );
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
    void setTimer(const int &msec);

    private:
    bool expired_timer;
    QTimer timer;

    private slots:
    void forceUpdate();
    };

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;
    TModel *model;
    QTreeView *view;
    };

    #endif // MAINWINDOW_H @

    mainwindow.cpp
    @#include "mainwindow.h"
    #include "ui_mainwindow.h"

    #include <cstdlib>

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    view = new QTreeView();
    model = new TModel(0, 22, view);
    view->setModel(model);
    setCentralWidget(view);

    for (unsigned int i = 0; i < 300; i++)
    {
    model->insertRow(model->rowCount());
    model->setData(model->index(i,0), i+1);
    for (unsigned int c = 1; c < model->columnCount(); c++)
    {
    model->setData(model->index(i,c), rand());
    }
    }
    model->setTimer(750);
    }

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

    TModel::TModel( int rows, int columns, QObject * parent): QStandardItemModel(rows, columns, parent), expired_timer(false)
    {
    connect(&timer, SIGNAL(timeout()), SLOT(forceUpdate()));
    }

    void TModel::setTimer(const int &msec)
    {
    timer.stop();
    timer.start(msec);
    }

    bool TModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if (expired_timer) blockSignals(true);
    bool ret = QStandardItemModel::setData(index, value, role);
    if (expired_timer) blockSignals(false);
    return ret;
    }

    void TModel::forceUpdate()
    {
    expired_timer = true;
    for (unsigned int i = 0; i < rowCount(); i++)
    {
    for (unsigned int c = 1; c < columnCount(); c++)
    {
    setData(index(i,c), rand());
    }
    }

    emit dataChanged(index(0,0), index(rowCount()-1 ,columnCount()-1));
    expired_timer = false;
    } @

    mainwindow.ui
    @<?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
    <class>MainWindow</class>
    <widget class="QMainWindow" name="MainWindow">
    <property name="geometry">
    <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
    </rect>
    </property>
    <property name="windowTitle">
    <string>MainWindow</string>
    </property>
    <widget class="QWidget" name="centralWidget"/>
    </widget>
    <layoutdefault spacing="6" margin="11"/>
    <resources/>
    <connections/>
    </ui>@

    untitled.pro
    @#-------------------------------------------------

    Project created by QtCreator 2013-04-28T15:53:26

    #-------------------------------------------------

    QT += core gui

    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    TARGET = untitled
    TEMPLATE = app

    SOURCES += main.cpp
    mainwindow.cpp

    HEADERS += mainwindow.h

    FORMS += mainwindow.ui @

    1 Reply Last reply
    0
    • JeroentjehomeJ Offline
      JeroentjehomeJ Offline
      Jeroentjehome
      wrote on last edited by
      #2

      Oke, try to use the datachanged in the setData function only for the item that will be changed into the model. The will make sure the GUI keep on running between the updates on screen when data is being changed.
      In the forceUpdate use the reset() signal, this will automaticly update the entire View, but takes LONG time when a large list is displayed.

      Greetz, Jeroen

      1 Reply Last reply
      0
      • S Offline
        S Offline
        sledgehammer_999
        wrote on last edited by
        #3

        emitting the dataChanged singal inside setData when I update ALL cells is horribly inefficient. It locks up the whole application for several seconds, and in the meantime the timer has expired again causing a chained reaction.

        If I use reset() in place of the emit dataChanged() it slightly improves the update with almost no noticeable gui freeze BUT: It has nasty drawback. The selected row is forgotten.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved