Results 1 to 17 of 17

Thread: QTableWidget Update - slow

  1. #1
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default QTableWidget Update - slow

    Hello,

    I am using a QTableWidget to display 11 columns of data that I receive from a socket.
    I receive about 200 lines of data in under 2 seconds. Each line uses a thread to make the signal/slot call for the GUI to display the data. In the GUI class, a new row is created and the line of data is parsed into the 11 different columns on the display. For some reason to update the table with all 200 lines of data, it takes close to 20 seconds. I have time print-outs around the 11 column entries, and it looks like the call to 'setItem' is the bottleneck.
    Here's an example of one of the column entries:
    Qt Code:
    1. start2 = QTime::currentTime ();
    2.  
    3. tbl_item = new QTableWidgetItem (QTableWidgetItem (QString (value_char)));
    4. the_table->setItem ( location_index, column, tbl_item );
    5.  
    6. end2 = QTime::currentTime ();
    7. elsp = (end2.second () - start2.second ());
    8. if (elsp > 0)
    9. logMessage (PRIORITY_DEBUG, "Elapsed flop Secs %u.%.3u",
    10. elsp,
    11. (end2.msec () - start2.msec ()));
    To copy to clipboard, switch view to plain text mode 


    I'm using a QTableWidget to take advantage of its search capabilities so I can make sure I am not adding duplicate data to the Table and I can update existing entries.
    How I call the search:
    Qt Code:
    1. QList<QTableWidgetItem*> results_list = the_table->findItems (QString::number(game_id), Qt::MatchExactly);
    To copy to clipboard, switch view to plain text mode 

    Should I use QTableView instead? Is it faster to add rows into the table?
    What about QTableView's search capabilities, are they better than the search for QTableWidget? Does the Model/View architecture help with this?

    Thanks,
    DP

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by DPinLV
    What about QTableView's search capabilities, are they better than the search for QTableWidget?
    You can make them faster or even implement your model in such way, that they won't be needed just to check whether you should add the data or not.

    http://www.qtcentre.org/forum/f-qt-p...view-2888.html

  3. The following user says thank you to jacek for this useful post:

    DPinLV (16th August 2006)

  4. #3
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    Jacek,

    I switch my table to QTableView and I created a custom Model derived from QAbstractTableModel. Unfortunately, the display is slower than before, I must have done something wrong.
    In the class I have a vector of a specfic class that contains a vector of objects (a struct with a char string and its length).
    When I add new rows I put the data into the vector
    Qt Code:
    1. bool MyGameModel::insertRow(TabbedDataParser* tab_data_parser, const QModelIndex &index)
    2. {
    3. bool result = false;
    4.  
    5. if (0 != tab_data_parser)
    6. {
    7. TabbedDataParser* new_data = new TabbedDataParser ();
    8. int position = m_data_container.size ();
    9.  
    10. position = index.column ();
    11. *new_data = *tab_data_parser;
    12. m_data_container.push_back (new_data);
    13. result = true;
    14. }
    15.  
    16. return result;
    17. }
    To copy to clipboard, switch view to plain text mode 

    When the data is retrieved, I use the index.row to get the data from the vector, and then use my specialized obhject, to get the column data. These seems straight forward, yet I'm not gettig any improvements.
    Qt Code:
    1. QVariant MyGameModel::data(const QModelIndex& index, int role) const
    2. {
    3. QVariant data;
    4.  
    5. if (index.isValid())
    6. {
    7. ///EVEN DOING THIS IS SLOW
    8. data = QString ("Well? %1").arg (index.column ());
    9. return data;
    10.  
    11. if (Qt::DisplayRole == role)
    12. {
    13. // Get the data item
    14. int container_size = m_data_container.size ();
    15. if ((index.row () < container_size) && (index.column () < m_column_count))
    16. {
    17. TabbedDataParser* cached_data = (TabbedDataParser*)m_data_container[index.row ()];
    18. if (0 != cached_data)
    19. {
    20. char* value_char = 0;
    21. int column = index.column ();
    22. GameUpdateIndices data_index = UPDATE_INDEX_UNKNOWN;
    23.  
    24. switch (column)
    25. {
    26. case GAME_ID_COLUMN:
    27. data_index = ID;
    28. break;
    29. case GAME_NAME_COLUMN:
    30. data_index = NAME;
    31. break;
    32. case GAME_WAITING_COLUMN:
    33. data_index = PLAYERS_WAITING;
    34. break;
    35. default:
    36. break;
    37. }
    38.  
    39. if ((UPDATE_INDEX_UNKNOWN != data_index) && (cached_data->getDataValue (data_index, value_char)))
    40. {
    41. data = value_char;
    42. }
    43. }
    44. }
    45. }
    46. }
    47.  
    48. return data;
    49. }
    To copy to clipboard, switch view to plain text mode 

    I also overrode the methods for the column header data which is a QStringList of data.
    Qt Code:
    1. QVariant MyGameModel::headerData (int section, Qt::Orientation orientation, int role) const
    2. {
    3. QVariant result;
    4.  
    5. if (section < m_header_strings.count ())
    6. {
    7. result = m_header_strings [section];
    8. }
    9.  
    10. return result;
    11. }
    12.  
    13. bool MyGameModel::setHeaderData (int section, Qt::Orientation orientation, const QVariant& value, int role)
    14. {
    15. m_header_strings = (m_header_strings << value.toString ());
    16.  
    17. return true;
    18. }
    To copy to clipboard, switch view to plain text mode 


    I attach the model to TableView as such:
    Qt Code:
    1. ui.m_Table->setModel (m_theModel);
    To copy to clipboard, switch view to plain text mode 

    And data is added like this:
    Qt Code:
    1. m_theModel->insertRow ((TabbedDataParser*)&parsed_data);
    To copy to clipboard, switch view to plain text mode 

    Do you see anything I missed?

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by DPinLV
    When I add new rows I put the data into the vector
    What is the type of this vector? std::vector? AFAIR STL is awfully slow under windows (but I don't remember whose implementation).

    You don't invoke beginInsertRows() and endInsertRow() in MyGameModel::insertRow().

  6. #5
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    I use a QVector on Windows XP
    Qt Code:
    1. QVector<TabbedDataParser*> m_data_container;
    To copy to clipboard, switch view to plain text mode 

    Sorry, I had removed the begin/end insert calls to see if they were necessary in insertRow vs. insertRows. I have added them back in and there is still no improvement.

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

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by jacek
    You don't invoke beginInsertRows() and endInsertRow() in MyGameModel::insertRow().
    This shouldn't influence the speed so much.

    My guess is, apart from anything else, that the other thread may be starving the model. Is this other thread really necessary? Or maybe you could add data by blocks and not one by one? Hundred messages per second need to be inserted into the queue and retrieved from it and processed, that's much work. Maybe you could use something like this:

    Qt Code:
    1. QMutex mutex;
    2. QList<TabbedDataParser*> sharedlist;
    3.  
    4. // "worker" thread:
    5. mutex.lock();
    6. bool needSignal = sharedlist.isEmpty();
    7. sharedlist << new TabbedDataParser(...);
    8. if(needSignal) emit newData();
    9. mutex.unlock();
    10.  
    11. // "gui" thread
    12. void GUIThreadClass::slotConnectedToNewData(){
    13. mutex.lock();
    14. while(!sharedlist.isEmpty()){
    15. TabbedDataParser *elem = sharedlist.front();
    16. sharedlist.pop_front();
    17. processData(elem);
    18. }
    19. mutex.unlock();
    20. }
    To copy to clipboard, switch view to plain text mode 

    You can still improve it. The code I wrote blocks the worker thread while the main thread processes data. You can make it that the list is only locked by the main thread when it actually retrieves data from it and when it processes the data, the other thread could still insert new items. Something like this could work:
    Qt Code:
    1. void GUIThreadClass::slotConnectedToNewData(){
    2. forever{
    3. mutex.lock();
    4. if(sharedlist.isEmpty()){
    5. mutex.unlock(); break;
    6. }
    7. TabbedDataParser *elem = sharedlist.front();
    8. sharedlist.pop_front();
    9. mutex.unlock();
    10. processData(elem);
    11. }
    12. }
    To copy to clipboard, switch view to plain text mode 

    This way instead of emitting 200 signals (which end up in the event queue), you emit one or two.
    Last edited by wysota; 17th August 2006 at 21:51.

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

    DPinLV (17th August 2006)

  9. #7
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    wysota,

    I think I am doing something similar to what you suggest.
    I receive data from a socket and I call a method that put data into a queue for retrieval by my worker thread.
    Qt Code:
    1. void TableHandlingThread::addParsedDataQueue (int selected_view, const char* message, int message_length)
    2. {
    3. if ((0 != message) && (message_length > 0))
    4. {
    5. // Add to a vector
    6. SignalDataContainerClass* signal_data = new SignalDataContainerClass ();
    7.  
    8. signal_data->init (selected_view, message, message_length, 0);
    9. m_queue_mutex.lock ();
    10. m_data_container_queue.insert (m_data_container_queue.begin (), signal_data);
    11. m_wait_trigger.wakeAll ();
    12. m_queue_mutex.unlock ();
    13. }
    14. }
    To copy to clipboard, switch view to plain text mode 


    The worker thread gets the trigger, drains the queue, and passes the message onto the gui thread for display. Where, m_data_container_queue, is a std::vector...
    Qt Code:
    1. void TableHandlingThread::run ()
    2. {
    3. // Get the data from the queue and display it.
    4. bool stop_thread = false;
    5. int selected_view = 0;
    6.  
    7. // Set up the signal and slot for the data container
    8. qRegisterMetaType< SignalDataContainerClass >( "SignalDataContainerClass" );
    9. QObject::connect(m_emitter_class,
    10. SIGNAL(dataContainerSignal (const SignalDataContainerClass& )),
    11. m_pkr_receiver_class,
    12. SLOT(receiveContainerDataSlot (const SignalDataContainerClass& )),
    13. Qt::QueuedConnection);
    14.  
    15. QObject::connect(m_emitter_class,
    16. SIGNAL(removeGameSignal (int , int )),
    17. m_pkr_receiver_class,
    18. SLOT(sendRemoveGameIDDataSender (int, int)),
    19. Qt::QueuedConnection);
    20.  
    21. while (true)
    22. {
    23. SignalDataContainerClass* signal_data;
    24.  
    25. m_queue_mutex.lock ();
    26. if (!m_data_container_queue.size ())
    27. {
    28. m_wait_trigger.wait (&m_queue_mutex);
    29. }
    30.  
    31. // Get the stop variable
    32. stop_thread = m_shutdown;
    33. if (!stop_thread)
    34. {
    35. // Get item from queue
    36. signal_data = m_data_container_queue.back ();
    37. m_data_container_queue.pop_back ();
    38. }
    39. m_queue_mutex.unlock ();
    40.  
    41. if (stop_thread)
    42. {
    43. break;
    44. }
    45.  
    46. if ((0 != signal_data) && (0 != m_emitter_class))
    47. {
    48. if (signal_data->m_message_length > 0)
    49. {
    50. m_emitter_class->sendDataContainerForSignal (*signal_data);
    51. }
    52. delete signal_data;
    53. }
    54. }
    55. }
    56. ...
    57. void TableHandlingThreadEmitter::sendDataContainerForSignal (const SignalDataContainerClass& table_data)
    58. {
    59. emit dataContainerSignal (table_data);
    60. }
    To copy to clipboard, switch view to plain text mode 

    Does that accomplish the same as you suggest?

  10. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by wysota
    This shouldn't influence the speed so much.
    Where did I write that it has any influence on the speed?

  11. #9
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    Also, the slot method, receiveContainerDataSlot, is where the TabbedDataParser object is created and the insertRow call is made.

  12. #10
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by jacek
    What is the type of this vector? std::vector? AFAIR STL is awfully slow under windows (but I don't remember whose implementation).

    You don't invoke beginInsertRows() and endInsertRow() in MyGameModel::insertRow().
    jacek,
    Are these calls necessary for insertRow and insertRows?

  13. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by DPinLV
    Are these calls necessary for insertRow and insertRows?
    Yes, you need them to inform the view that model was updated.

  14. The following user says thank you to jacek for this useful post:

    DPinLV (17th August 2006)

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

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by DPinLV
    Does that accomplish the same as you suggest?
    No, you still emit a queued signal for every item. Each signal gets queued in the event queue and is processed separately later on. Either don't use that signal/slot mechanism at all here (if all that thread does is to wait for data and then emit it back into the queue, then you can safely skip it and do everything in a single thread without using the wait condition (you can do it in the slot after receiving data from network)) or limit the number of signals emitted.

    And don't insert items one at a time into the model. And if you insert a group of items into the model at a time, either insert them at once (so that beginInsertRows and endInsertRows is called only once) or disable update of all views connected to the model (but the former should be easier to achieve).

    Quote Originally Posted by jacek
    Where did I write that it has any influence on the speed?
    I'm sure you did! You must have changed your post afterwards! Damn you administrators!

    And more seriously, where did I write that you had written it had any influence on speed (remember "reported speech" -- "what has you done wiz your teacher!")?

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

    DPinLV (17th August 2006)

  17. #13
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by wysota
    And don't insert items one at a time into the model. And if you insert a group of items into the model at a time, either insert them at once (so that beginInsertRows and endInsertRows is called only once) or disable update of all views connected to the model (but the former should be easier to achieve).
    I'm not sure there is any way to get around inserting the messages unless I sleep on the queue that drains them??? The idea is to display messages as they arrive on the socket.
    In any case, I thought you could not invoke widget methods from non GUI threads?

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

    Default Re: QTableWidget Update - slow

    But you can do network operations in the gui thread. And don't try to insert 200 entries a second one by one, your views will starve your app as they'll try to refresh themselves after every endInsertRows().

    The solution I proposed before makes use of the fact that often you can process entries slower that they are generated, which enlarges the queue, causes more and more delays and causes a lock when you run out of some resource (for example buffer space). This is of course a problem, but you can change it to an asset if you add entries to the buffer as usual, but remove them not one by one, but all at once. This way you free the resource (queue) and can process entries "as fast as possible" -- remember there is no "immediately" in computer world. The user won't notice the difference if an entry is processed now or 10us later, as long as the order of items is preserved.

    Each signal emition makes an overhead, each mutex lock makes an overhead. Each context change makes an overhead. Try to avoid them.
    Last edited by wysota; 17th August 2006 at 23:03.

  19. #15
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    I'm not sure that applies to my model.
    My socket operations are handled by an in-house developed library that uses asynchronous socket operations and its own thread pool (all strictly C++ no QT).

    I assume this is why the GUI does not update when I make calls from the socket receive callback method. Then, I used the slot/signal approach so that when the socket callback received data it put in a queue that a QThread drained and sent to the slot on the GUI class. I see what you mean that if I call this 200 times, there are 200 emits and therefor 200 gui drawing emits as well. But, I feel that in my situation there is no other way since my socket stuff is not apart of the GUI thread.

    Another thing I noticed is am I overriding the QAbstractItemModel methods correctly? I wasn't sure how to get my data into the model so my insertRow method is as such:
    Qt Code:
    1. bool insertRow(TabbedDataParser* tab_data_parser, const QModelIndex &index = QModelIndex())
    To copy to clipboard, switch view to plain text mode 

    even though the signature of the QAbstrctItemModel class is
    Qt Code:
    1. bool QAbstractItbool QAbstractItemModel::insertRow ( int row, const QModelIndex & parent = QModelIndex() )
    To copy to clipboard, switch view to plain text mode 

    Is that an issue?

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

    Default Re: QTableWidget Update - slow

    Quote Originally Posted by DPinLV
    My socket operations are handled by an in-house developed library that uses asynchronous socket operations and its own thread pool (all strictly C++ no QT).
    That makes it more complicated...

    But, I feel that in my situation there is no other way since my socket stuff is not apart of the GUI thread.
    Of course there is... don't insert one row at a time

    Another thing I noticed is am I overriding the QAbstractItemModel methods correctly? I wasn't sure how to get my data into the model so my insertRow method is as such:
    Qt Code:
    1. bool insertRow(TabbedDataParser* tab_data_parser, const QModelIndex &index = QModelIndex())
    To copy to clipboard, switch view to plain text mode 

    even though the signature of the QAbstrctItemModel class is
    Qt Code:
    1. bool QAbstractItbool QAbstractItemModel::insertRow ( int row, const QModelIndex & parent = QModelIndex() )
    To copy to clipboard, switch view to plain text mode 
    You are not overriding the insertRow method, because it has a different signature. But that's ok, you can have your own methods for manipulating the model. But I still suggest you insert a whole bunch of items at one go (using a custom method, of course).

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

    DPinLV (18th August 2006)

  22. #17
    Join Date
    Jul 2006
    Posts
    33
    Thanks
    14
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTableWidget Update - slow

    wysota and jacek,

    I have changed some things around and I am able to make multiple row updates where possible and it is definitely faster.

    Thanks,
    DP

Similar Threads

  1. Replies: 5
    Last Post: 27th May 2006, 13:44
  2. Replies: 6
    Last Post: 5th March 2006, 21:05
  3. Updating a QTableWidget through a Dialog
    By dragon in forum Newbie
    Replies: 3
    Last Post: 19th January 2006, 21:16
  4. Update a row
    By dragon in forum Newbie
    Replies: 9
    Last Post: 17th January 2006, 17:11
  5. How to obtain the width of a QTableWidget?
    By Giel Peters in forum Qt Programming
    Replies: 3
    Last Post: 9th January 2006, 22:34

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.