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. QTableView performance: slow repaint of scroll area viewport
Forum Updated to NodeBB v4.3 + New Features

QTableView performance: slow repaint of scroll area viewport

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 190 Views 2 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
    svadym
    wrote last edited by
    #1

    Hi everyone!
    I would like to ask you if the behavior that I see is normal and expected in debug builds.

    Context:
    I'm working on a CAN bus tool which has to display received and decoded frames or messages. I use QTableView + custom model with a vector of messages inside. Table view gets data by simple memory access via index with no additional calculation or formatting.
    I noticed that no matter what the model does, any update of the model triggers QEvent::Paint of qt_scrollarea_viewport of the QTableView which usually takes 30-120 ms. even in very simple cases and small number of rows.

    Simplified example:
    Toolchain: MCVS 2019 64 bit
    Qt: 5.15.2
    OS: Windows 10
    Build: debug
    Running from Qt Creator ("Run" button)

    #include "mainwindow.h"
    
    #include <QApplication>
    #include <QElapsedTimer>
    #include <QEvent>
    #include <QDebug>
    #include <QAbstractItemModel>
    #include <QTimer>
    
    class Application : public QApplication
    {
        QElapsedTimer timer;
    public:
        Application(int &argc, char **argv)
            : QApplication(argc, argv)
        {
    
        }
    
        bool notify(QObject *receiver, QEvent *event) override
        {
            const auto type = event->type();
            const auto name = receiver ? receiver->objectName() : QString{};
    
            timer.start();
            const bool ret = QApplication::notify(receiver, event);
            const auto elapsed = timer.elapsed();
    
            if(elapsed > 25)
                qWarning() << "Slow event detected:" << type << receiver << name << elapsed;
    
            return ret;
        }
    };
    
    class TestModel : public QAbstractTableModel
    {
    public:
        enum Roles { DataRole = Qt::UserRole };
        enum Columns { Time, MessageInfo, Data, Description, ColumnCount };
    
        explicit TestModel(QObject *parent = nullptr)
            : QAbstractTableModel(parent)
        {
    
        }
    
        void updateRow(int row)
        {
            if (row > rowCount())
                return;
    
            emit dataChanged(index(row, 0), index(row, columnCount() - 1));
        }
    
        void updateView()
        {
            emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
        }
    
        int rowCount(const QModelIndex & = QModelIndex()) const override {
            return 25;
        }
    
        int columnCount(const QModelIndex & = QModelIndex()) const override {
            return 4;
        }
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
        {
            switch (role)
            {
            case Qt::DisplayRole:
                return QStringLiteral("%1:%2").arg(index.row() + 1).arg(index.column() + 1);
            }
    
            return {};
        }
    };
    
    int main(int argc, char *argv[])
    {
        Application a(argc, argv);
        MainWindow w;
        TestModel model;
        int row = 0;
    
        QTimer updateTimer;
        updateTimer.setInterval(100);
        QObject::connect(&updateTimer, &QTimer::timeout, [&](){
            //qDebug() << "Update timer timeout";
            model.updateRow(row);
    
            // update one row per timeout
            if (++row >= model.rowCount())
                row = 0;
        });
    
        w.setTableModel(&model);
        updateTimer.start();
    
        w.show();
    
        return a.exec();
    }
    
    
    

    Note: MainWindow is auto-generated form with QTableView inside. MainWindow::setTableModel just calls QTableView::setModel

    It seems doesn't matter how frequently we update the model, every 50 ms. or 1 second. Repaint event takes the same amount of time. The time increases with increasing view port size.

    Even so in release builds it works well and snappy, I still see accidental, slow (50-100 ms.) repaints in release mainly when I resize, mode or change focus of the main window, probably it's normal, but please let me know if it's ok that it still takes up to 100 ms.

    Here is piece of a log from debug build:

    ...
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 76
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 77
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 79
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 80
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 81
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 81
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 82
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 83
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 81
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 82
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 73
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 74
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 73
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 74
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 75
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 76
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 79
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 80
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 75
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 75
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 75
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 76
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 75
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 75
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 75
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 76
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 76
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 77
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 80
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 81
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 79
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 80
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 92
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 93
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 86
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 78
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 77
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 78
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 77
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 79
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 84
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 85
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 82
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 83
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 83
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 84
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 76
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 77
    Update timer timeout
    Slow event detected: QEvent::Paint QWidget(0x2f1a784aea0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 76
    Slow event detected: QEvent::UpdateRequest MainWindow(0xf414cff9a0, name = "MainWindow") "MainWindow" 77
    ...
    

    and screenshot:table_view_test.png

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote last edited by
      #2

      Hi and welcome to devnet,

      If you sample code is a good substitute with what happens with your real application, you trigger a full repaint because you are telling the view that all cells have changed for all roles which is not the right thing to do.
      There are some optimization that you can apply such as telling the view that you are using uniform height and that kind of things that helps.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      S 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi and welcome to devnet,

        If you sample code is a good substitute with what happens with your real application, you trigger a full repaint because you are telling the view that all cells have changed for all roles which is not the right thing to do.
        There are some optimization that you can apply such as telling the view that you are using uniform height and that kind of things that helps.

        S Offline
        S Offline
        svadym
        wrote last edited by
        #3

        @SGaist Hi and thank you for your feedback.

        I've updated my emit dataChanged:

        void updateRow(int row)
        {
            if (row > rowCount())
                return;
        
            emit dataChanged(index(row, 0), index(row, columnCount() - 1), {Qt::DisplayRole});
        }
        

        Repaint time remains the same unfortunately. In any case, it's very good hint and will improve performance of my app. Thank you.

        Regarding the uniform height: from what I saw QTableView doesn't have setUniformRowHeights. During the test I used the following configuration of the vertical header:
        vheader.png
        However, I'm not sure if it has the same effect. Or should I add Qt::SizeHintRole to my model and return fixed height?

        1 Reply Last reply
        0
        • S Offline
          S Offline
          svadym
          wrote last edited by
          #4

          As it was advised here, I've set fixed section resize policy for the vertical header:

          #include "mainwindow.h"
          #include "ui_mainwindow.h"
          
          MainWindow::MainWindow(QWidget *parent)
              : QMainWindow(parent)
              , ui(new Ui::MainWindow)
          {
              ui->setupUi(this);
          
              if (auto vheader = ui->tableView->verticalHeader()) {
                  vheader->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
                  vheader->setDefaultSectionSize(30);
              }
          }
          
          MainWindow::~MainWindow()
          {
              delete ui;
          }
          
          void MainWindow::setTableModel(QAbstractTableModel *model)
          {
              ui->tableView->setModel(model);
          }
          

          However, no changes in debug build. Thus, I can only assume that repaint is an actual bottleneck here, or I'm missing something else.

          1 Reply Last reply
          0
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote last edited by
            #5

            Updating a model with 20Hz is not really useful - Noone will see this. Also update to a recent Qt version.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            Pl45m4P S 2 Replies Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              Updating a model with 20Hz is not really useful - Noone will see this. Also update to a recent Qt version.

              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote last edited by
              #6

              @Christian-Ehrlicher said in QTableView performance: slow repaint of scroll area viewport:

              Noone will see this

              Fluent video picture motion for humans starts at around 24/25 Hz... so you can see changing values :) Still might not make too much sense to update the whole view.


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              S 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                Updating a model with 20Hz is not really useful - Noone will see this. Also update to a recent Qt version.

                S Offline
                S Offline
                svadym
                wrote last edited by svadym
                #7

                @Christian-Ehrlicher fair point regarding 20Hz, but as I mentioned even if we update model every second, it's noticeable that UI "delays" for more than 50-100 ms. when you interact with it.

                Regarding recent Qt version, I also have Qt 6.6.1 installed and it seems behave better when window/viewport is static. There are no expensive repaint events even if model emits dataChanged.

                However, it still lags in debug build when I resize or change visibility of a main window:

                Slow event detected: QEvent::Paint QWidget(0x235ac867ec0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 109
                Slow event detected: QEvent::Paint QWidget(0x235ac867ec0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 109
                Slow event detected: QEvent::UpdateRequest MainWindow(0xb3ce2ff620, name = "MainWindow") "MainWindow" 110
                Slow event detected: QEvent::Paint QWidget(0x235ac867ec0, name = "qt_scrollarea_viewport") "qt_scrollarea_viewport" 173
                

                Anyways, lagging during window resize in debug build is tolleratale. It's usable at least.

                1 Reply Last reply
                0
                • Pl45m4P Pl45m4

                  @Christian-Ehrlicher said in QTableView performance: slow repaint of scroll area viewport:

                  Noone will see this

                  Fluent video picture motion for humans starts at around 24/25 Hz... so you can see changing values :) Still might not make too much sense to update the whole view.

                  S Offline
                  S Offline
                  svadym
                  wrote last edited by svadym
                  #8

                  @Pl45m4 said in QTableView performance: slow repaint of scroll area viewport:

                  Still might not make too much sense to update the whole view

                  I'm emitting dataChanged only for updated rows and (now) only display role, so the update scope is limited)
                  The idea was to have smooth value changing (frame counts, cycle times...) when frames arrive under 100 ms. period for example. Otherwise, you could see value change in jumps/steps. In any case, it works well in release build, even with 20Hz model update frequency

                  My main concern was to know if it's expected behavior in debug configuration or there is just some problem in the way how I manage model and data updates.

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote last edited by
                    #9

                    Please provide a minimal compileable example in a bug report with a recent Qt version. Also the OS is important. I never seen such slow times on machine here. MacOS has some issues but I don't care since I don't use it.

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    S 1 Reply Last reply
                    0
                    • Christian EhrlicherC Christian Ehrlicher

                      Please provide a minimal compileable example in a bug report with a recent Qt version. Also the OS is important. I never seen such slow times on machine here. MacOS has some issues but I don't care since I don't use it.

                      S Offline
                      S Offline
                      svadym
                      wrote last edited by svadym
                      #10

                      @Christian-Ehrlicher I can try to submit a bug report if you say that it's not normal.

                      Setup info:
                      Qt: 5.15.2 (MCVS 2019 32 bit), 6.6.1 (MCVS 2019 64 bit)
                      OS: Windows 10
                      Build: debug
                      Running from Qt Creator ("Run" button)

                      Christian EhrlicherC 1 Reply Last reply
                      0
                      • S svadym

                        @Christian-Ehrlicher I can try to submit a bug report if you say that it's not normal.

                        Setup info:
                        Qt: 5.15.2 (MCVS 2019 32 bit), 6.6.1 (MCVS 2019 64 bit)
                        OS: Windows 10
                        Build: debug
                        Running from Qt Creator ("Run" button)

                        Christian EhrlicherC Offline
                        Christian EhrlicherC Offline
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote last edited by
                        #11

                        @svadym said in QTableView performance: slow repaint of scroll area viewport:

                        I can try to submit a bug report if you say that it's not normal.

                        This would be nice. With a small reproducer (main.cpp only), a recent Qt version (6.9 and up) and some benchmark results from you. Also reduce the update rate to e.g. 10hz. It's fast enough - Noone can read that fast.

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        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