Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML TableView refresh in realtime only updates UI every 1 second
Forum Update on Monday, May 27th 2025

QML TableView refresh in realtime only updates UI every 1 second

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 3 Posters 1.3k Views
  • 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.
  • P Offline
    P Offline
    Paul Svetlichny
    wrote on last edited by Paul Svetlichny
    #1

    Hi there!
    I have a task of showing big amount of data in realtime (as close to that as possible) with UI update every 10 to 100ms (best to worst values), I've managed to create a test model generating random numbers and populating the table view with new set of random values with a Timer. I tried to set different time intervals from 1 to 100 ms, and I can see the timer fires and the new set of data is created, but the UI updates strictly in 1 second every time despite the timer interval value.
    Can you guide me on how to handle UI updates in less than 1 second.

    P.S.: I tried different amount of data from tables of 50x1000 to just 50x50. Every time I get UI update rate of 1 second.

    Update:

    It is based on the "Game Of Life" Qt example, so some of the elements are just not used and are obsolete, but as soon as they are "disabled" I think they don't make any influence on the rest of the code and the problem itself.
    You can see that in nextStep() method I invoke timestamp logging to console and I can see in the output that the method is invoked according to the timer, but the UI only updates visually every second.

    main.qml

    ApplicationWindow {
        id: root
        visible: true
        width: 760
        height: 810
        minimumWidth: 475
        minimumHeight: 300
    
        color: "#09102B"
        title: qsTr("Conway’s Game of Life")
    
        //! [tableview]
        TableView {
            id: tableView
            anchors.fill: parent
    
            rowSpacing: 1
            columnSpacing: 1
    
            ScrollBar.horizontal: ScrollBar {}
            ScrollBar.vertical: ScrollBar {}
    
            delegate: Rectangle {
                id: cell
                implicitWidth: 45
                implicitHeight: 15
    
                color: model.value > 100 ? "#f3f3f4" : "#b5b7bf"
                Label {
                    width: parent.width
                    height: parent.height
                    text: model.value
                }
            }
            //! [tableview]
    
            //! [model]
            model: GameOfLifeModel {
                id: gameOfLifeModel
            }
            //! [model]
    
            //! [scroll]
            contentX: 0;
            contentY: 0;
            //! [scroll]
        }
    
        footer: Rectangle {
            signal nextStep
    
            id: footer
            height: 50
            color: "#F3F3F4"
    
            RowLayout {
                anchors.centerIn: parent
    
                //! [next]
                Button {
                    text: qsTr("Next")
                    onClicked: gameOfLifeModel.nextStep()
                }
                //! [next]
    
                Item {
                    width: 50
                }
    
                Button {
                    text: timer.running ? "❙❙" : "▶️"
                    onClicked: timer.running = !timer.running
                }
            }
    
            FpsItem {
                    id: fpsItem
                    anchors.left: parent
                    color: "black"
            }
    
            Timer {
                id: timer
                interval: 10
                running: true
                repeat: true
    
                onTriggered: gameOfLifeModel.nextStep()
            }
        }
    }
    

    gameoflifemodel.cpp

    GameOfLifeModel::GameOfLifeModel(QObject *parent)
        : QAbstractTableModel(parent)
    {
    }
    
    //! [modelsize]
    int GameOfLifeModel::rowCount(const QModelIndex &parent) const
    {
        if (parent.isValid())
            return 0;
    
        return height;
    }
    
    int GameOfLifeModel::columnCount(const QModelIndex &parent) const
    {
        if (parent.isValid())
            return 0;
    
        return width;
    }
    //! [modelsize]
    
    //! [read]
    QVariant GameOfLifeModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid() || role != CellRole)
            return QVariant();
    
        return m_state[index.column()][index.row()];
    }
    //! [read]
    
    //! [write / not used]
    bool GameOfLifeModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        if (role != CellRole || data(index, role) == value)
            return false;
    
        m_state[index.column()][index.row()] = value.toBool();
        emit dataChanged(index, index, {role});
    
        return true;
    }
    //! [write]
    
    Qt::ItemFlags GameOfLifeModel::flags(const QModelIndex &index) const
    {
        if (!index.isValid())
            return Qt::NoItemFlags;
    
        return Qt::ItemIsEditable;
    }
    
    //! [update]
    void GameOfLifeModel::nextStep()
    {
        srand(time(NULL));
    
        qDebug() << QTime::currentTime().toString("yyyy/MM/dd hh:mm:ss,zzz");
    
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                m_state[j][i] = (rand() % 1000) + 1;
            }
        }
    
        emit dataChanged(index(0, 0), index(height - 1, width - 1), {CellRole});
    }
    //! [update]
    

    gameoflifemodel.h

    //! [modelclass]
    class GameOfLifeModel : public QAbstractTableModel
    {
        Q_OBJECT
    
        Q_ENUMS(Roles)
    public:
        enum Roles {
            CellRole
        };
    
        QHash<int, QByteArray> roleNames() const override {
            return {
                { CellRole, "value" }
            };
        }
    
        explicit GameOfLifeModel(QObject *parent = nullptr);
    
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        bool setData(const QModelIndex &index, const QVariant &value,
                     int role = Qt::EditRole) override;
    
        Qt::ItemFlags flags(const QModelIndex &index) const override;
    
        Q_INVOKABLE void nextStep();
    
    private:
        static constexpr int width = 50;
        static constexpr int height = 50;
        static constexpr int size = width * height;
    
        template <class T, size_t ROW, size_t COL>
        using NativeMatrix = T[ROW][COL];
        NativeMatrix<int, height, width> m_state;
    };
    //! [modelclass]
    

    Thank you!

    1 Reply Last reply
    0
    • P Offline
      P Offline
      Paul Svetlichny
      wrote on last edited by
      #5

      Okay, the problem is solved. The issue appeared to be in the random number generation process, not in the table view.
      In the code I used

      srand(time(NULL))
      

      The time(NULL) returns seconds and not milliseconds, thus I was getting the same numbers and they were updated only after 1 second. In order to solve this I switched to using this to generate random numbers and everything worked well:

          struct timespec ts;
          clock_gettime(CLOCK_MONOTONIC, &ts);
      
          /* using nano-seconds instead of seconds */
          srand((time_t)ts.tv_nsec);
      
      1 Reply Last reply
      1
      • GrecKoG Offline
        GrecKoG Offline
        GrecKo
        Qt Champions 2018
        wrote on last edited by
        #2

        Please share a minimalist reproducible example so we can help you.

        P 1 Reply Last reply
        0
        • P Offline
          P Offline
          Paul Svetlichny
          wrote on last edited by Paul Svetlichny
          #3

          Sorry, updated my question with details.

          1 Reply Last reply
          0
          • GrecKoG GrecKo

            Please share a minimalist reproducible example so we can help you.

            P Offline
            P Offline
            Paul Svetlichny
            wrote on last edited by
            #4

            @GrecKo Any ideas? Thanks.

            1 Reply Last reply
            0
            • P Offline
              P Offline
              Paul Svetlichny
              wrote on last edited by
              #5

              Okay, the problem is solved. The issue appeared to be in the random number generation process, not in the table view.
              In the code I used

              srand(time(NULL))
              

              The time(NULL) returns seconds and not milliseconds, thus I was getting the same numbers and they were updated only after 1 second. In order to solve this I switched to using this to generate random numbers and everything worked well:

                  struct timespec ts;
                  clock_gettime(CLOCK_MONOTONIC, &ts);
              
                  /* using nano-seconds instead of seconds */
                  srand((time_t)ts.tv_nsec);
              
              1 Reply Last reply
              1
              • GrecKoG Offline
                GrecKoG Offline
                GrecKo
                Qt Champions 2018
                wrote on last edited by
                #6

                Why do you use srand at each step?

                1 Reply Last reply
                2
                • mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by mrjj
                  #7

                  Hi
                  just as a note.
                  rand() is not very random. or considered not optimal.
                  If you can use c++ 11 then look into the new random function

                  #include <random>
                  #include <iostream>
                  
                  int main() {
                      std::random_device rd;
                      std::mt19937 mt(rd());
                      std::uniform_real_distribution<double> dist(1.0, 10.0);
                  
                      for (int i=0; i<16; ++i)
                          std::cout << dist(mt) << "\n";
                  }
                  

                  https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

                  Its not critical/important if your Life game works.

                  1 Reply Last reply
                  3

                  • Login

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