Results 1 to 7 of 7

Thread: Model/View framework: streaming data in a QTableView

  1. #1
    Join Date
    Jun 2008
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Windows

    Question Model/View framework: streaming data in a QTableView

    Greetings,

    I am writing an application where I am receiving a lot of data from the network and have to display it in a QTableView. I can receive hundreds of messages per second and I need the table to remain responsive when data is added or changed. My function that updates the model looks like this:

    Qt Code:
    1. ModelItemRowTable::const_iterator rowIter = m_modelItemRows.find(symbol.c_str());
    2. if (m_modelItemRows.end() != rowIter)
    3. {
    4. int row = rowIter.value();
    5. m_modelItems[row].data.Update(quote, fieldUpdateFlags);
    6. emit dataChanged(index(row, 0), index(row, columnCount()-1));
    7. }
    8. else
    9. {
    10. emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
    11. ModelItem item;
    12. item.symbol = symbol.c_str();
    13. item.data = quote;
    14. m_modelItems.push_back(item);
    15. m_modelItemRows[symbol.c_str()] = m_modelItems.count() - 1;
    16. emit endInsertRows();
    17. }
    To copy to clipboard, switch view to plain text mode 

    where m_modelItems is a list of items and m_modelItemRows is a hash table storing the item rows as values for faster item lookup. This is a 3000 x 9 table.

    Now data insertion is very fast as it occurs when the model is created, the problem is when data is changed. I receive a lot of messages at a time and I was wondering how to do it without having to emit the dataChanged signal on every update. I have tried queuing the items and updating the range of queued items at regular intervals (e.g. every 100 ms, 250 ms, 1s) but the view is still not responsive enough and data is not updated as fast as I would like (1 to 4 times per second). Or maybe there is something about the dataChanged() signal that I am am missing?

    Any ideas?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Model/View framework: streaming data in a QTableView

    You don't have to emit the signal on every update. Update data in blocks (for instance group updates for each second) end emit a single signal afterwards.

  3. #3
    Join Date
    Jun 2008
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Windows

    Question Re: Model/View framework: streaming data in a QTableView

    I have tried something along those lines already by updating the range of items at regular time intervals. When I add a new item to the list of items in the model I keep track of the top and bottom updated rows. I also have a QTimer that will fire say every second and on timeout will update only the block of items between these top and bottom rows. Specifically:

    Qt Code:
    1. // This is where I update the model items
    2. ModelItemRowTable::const_iterator rowIter = m_modelItemRows.find(symbol.c_str());
    3. if (m_modelItemRows.end() != rowIter)
    4. {
    5. int row = rowIter.value();
    6. m_topUpdatedRow = (std::min)(m_topUpdatedRow, row);
    7. m_bottomUpdatedRow = (std::max)(m_bottomUpdatedRow, row);
    8. m_modelItems[row].data.Update(quote, fieldUpdateFlags);
    9. }
    10. else
    11. {
    12. emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
    13. ModelItem item;
    14. item.symbol = symbol.c_str();
    15. item.data = quote;
    16. m_modelItems.push_back(item);
    17. m_modelItemRows[symbol.c_str()] = m_modelItems.count() - 1;
    18. emit endInsertRows();
    19. }
    20.  
    21. // This is how I update a block of data in a separate slot that is run whem my timer times out
    22. emit dataChanged(index(m_topUpdatedRow, 0), index(m_bottomUpdatedRow, columnCount()-1));
    23. m_topUpdatedRow = (std::numeric_limits<int>::max)();
    24. m_bottomUpdatedRow = (std::numeric_limits<int>::min)();
    To copy to clipboard, switch view to plain text mode 

    Not much has changed and the GUI slows down to a crawl after the table is populated and the updates start rolling in. Any ideas? I am probably doing something horribly wrong but can't figure it out at the moment.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Model/View framework: streaming data in a QTableView

    When exactly is the snippet above executed? I think you still update one row at once...

  5. #5
    Join Date
    Jun 2008
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Model/View framework: streaming data in a QTableView

    I will clarify. The snippets are executed in two separate functions.

    Qt Code:
    1. void CModel::OnNewQuote(const std::string& symbol, const CQuote& quote, uint fieldUpdateFlags)
    2. {
    3. ModelItemRowTable::const_iterator rowIter = m_modelItemRows.find(symbol.c_str());
    4. if (m_modelItemRows.end() != rowIter)
    5. {
    6. int row = rowIter.value();
    7. m_topUpdatedRow = (std::min)(m_topUpdatedRow, row);
    8. m_bottomUpdatedRow = (std::max)(m_bottomUpdatedRow, row);
    9. m_modelItems[row].data.Update(quote, fieldUpdateFlags);
    10. }
    11. else
    12. {
    13. emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
    14. ModelItem item;
    15. item.symbol = symbol.c_str();
    16. item.data = quote;
    17. m_modelItems.push_back(item);
    18. m_modelItemRows[symbol.c_str()] = m_modelItems.count() - 1;
    19. emit endInsertRows();
    20. }
    21. }
    To copy to clipboard, switch view to plain text mode 

    The above function is a slot connected to a signal that will be emitted by the working thread when new data is received (I use a queued connection here). In my test case the row insertion part takes place only when the model is created as this is the only time I am populating the table. After that I am only updating existing entries in my table. In the above code, m_topUpdatedRow and m_bottomUpdatedRow are used to keep track of the block containing all of the updated rows.

    The model owns a QTimer that will time out at 1 second intervals. The timeout signal is connected to a slot that updates the table.

    Qt Code:
    1. void OnTimeOut()
    2. {
    3. emit dataChanged(index(m_topUpdatedRow, 0), index(m_bottomUpdatedRow, columnCount()-1));
    4. m_topUpdatedRow = (std::numeric_limits<int>::max)();
    5. m_bottomUpdatedRow = (std::numeric_limits<int>::min)();
    6. }
    To copy to clipboard, switch view to plain text mode 

    The slot resets m_topUpdatedRow and m_bottomUpdatedRow to "degenerate" values to ensure that they will be set to sensible values the next time a new quote is received.

    I am still observing the same problems and the table is still slow and unresponsive during updates.

  6. #6
    Join Date
    Jun 2008
    Posts
    6
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Model/View framework: streaming data in a QTableView

    I finally managed to test a release build today (couldn't do it before due to dependencies out of my control), and the table responds wonderfully in release mode, even if I emit a dataChanged() signal on every update. In debug mode even when I reduce the number of rows to say 50 or even 20 the table wasn't responsive. I did not expect such a huge difference between debug and release in this test.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Model/View framework: streaming data in a QTableView

    Well... this is wrong. You can't update the content and emit a signal "some time later". You still add one row at a time, instead of doing it all at once. I meant something like:

    Qt Code:
    1. // this one executed when new data is available
    2. void XXX::newContentAvailable(const Item &item){
    3. m_queue.enqueue(item);
    4. }
    5.  
    6. // this one executed once per second
    7. void XXX::performUpdate(){
    8. int topRow = rowCount();
    9. int bottomRow = -1;
    10. while(!m_queue.isEmpty()){
    11. Item item = m_queue.pop();
    12. // insert the item in the model
    13. if(row<topRow) topRow = row;
    14. if(row>bottomRow) bottomRow = row;
    15. }
    16. // emit one signal for all updates
    17. emit dataChanged(index(0, topRow), index(columnCount()-1, bottomRow));
    18. }
    To copy to clipboard, switch view to plain text mode 

  8. The following user says thank you to wysota for this useful post:

    yannickt (26th October 2008)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.