Results 1 to 6 of 6

Thread: QListWidget and takeItem() slow

  1. #1

    Default QListWidget and takeItem() slow

    Why is takeItem() horribly slow when used on more than 20 items in a list?

    I've come up with a work around but I need to clear my original lists. QListWidget::clear(), however, deletes my dynamically allocated pointers? Doesn't this go against everything in C++? So this brings me back to takeItem(), which sucks.

    Example:

    Qt Code:
    1. QListWidgetItem* item = currentList->item(0);
    2. QString str = item->text(); //fine
    3. currentList->clear();
    4. str = item->text(); //crashes
    To copy to clipboard, switch view to plain text mode 

    Am I doing something horribly wrong? My lists easily can contain over 1,000 items. Clear() is the only function that seems to 'clear' them fast, but my items are permanently deleted. This would be like if std::vector or std::map deleted pointers when you cleared. This is EXTREMELY frustrating.

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

    Default Re: QListWidget and takeItem() slow

    I don't see any use of takeItem() in the code you pasted. Are you sure this is the right code?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3

    Default Re: QListWidget and takeItem() slow

    The original code I was using:

    Qt Code:
    1. int pos = right_export->m_ui->lumpListView->currentRow() + 1;
    2.  
    3. if ( right_export->m_ui->lumpListView->count() == 0 )
    4. pos = 0;
    5.  
    6. int finalpos = currentList->row(list.at(0));
    7.  
    8. for( int i=0; i<list.size(); i++ ) {
    9.  
    10. QListWidgetItem* item = currentList->takeItem( currentList->row(list.at(i)) );
    11.  
    12. right_export->m_ui->lumpListView->insertItem(pos,item);
    13. right_export->m_ui->lumpListView->clearSelection();
    14. if ( pos >= right_export->m_ui->lumpListView->count() )
    15. pos = right_export->m_ui->lumpListView->count()-1;
    16. right_export->m_ui->lumpListView->setCurrentRow(pos);
    17. pos++;
    18.  
    19. }
    To copy to clipboard, switch view to plain text mode 

    It's fine as long as I don't have more than 20 items selected. Even if I do something simple like remove all items:

    Qt Code:
    1. while( currentList->count() )
    2. currentList->takeItem(0);
    To copy to clipboard, switch view to plain text mode 

    In that example if the list is even more than 100 items, it never returns. My code wasn't incorrect. I was simply pointing out that clear() makes no sense and goes against everything else in C++.

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

    Default Re: QListWidget and takeItem() slow

    Quote Originally Posted by deca5423 View Post
    My code wasn't incorrect.
    Yes, it was -- see below.

    I was simply pointing out that clear() makes no sense and goes against everything else in C++.
    Of course it makes sense. clear() is for clearing a list and clearing a list means getting rid of all the items in the list. If clear() wasn't deleting the items then to avoid memory leaks you would need a separate list where you kept all item pointers and it would be hard to synchronize that list with other actions that may be happening in your application. So the list is so to say "embedded" iinto the widget itself. If you don't want it to be -- use the model approach in which case you won't find a clear() method in QListView but rather (if at all) in the model. There is no reason clear() should not delete the items if they are owned by the widget. That's all in conformance with every design rules (C++ or no C++) I know.

    Now back to your code....

    Everytime you take the item out of the list the list is updated which means that it needs to do some calculations, inform its environment about the change by emitting proper signals and finally redraw itself. This happens with every remove so if you remove 1000 items one by one, you get 1000 of those. If you do it in one go - like clear() does - you only get one update so things are approximately 1000 faster. If you insisted on using takeItem() a more proper code would be:
    Qt Code:
    1. list->setUpdatesEnabled(false);
    2. list->blockSignals(); // optionally
    3. while(list->item(0)) // notice I'm not using count() which is also slow
    4. list->takeItem(0);
    5. list->unblockSignals(); // optionally
    6. list->setUpdatesEnabled(true);
    7. list->update(); // force update
    To copy to clipboard, switch view to plain text mode 
    I'm not sure if blocking signals will not make your application crash in this particular situation so you might want to avoid it.

    Another thing - I have no idea what the code you pasted is meant to do, I thing you overcomplicated it greatly. If you told us what was your intention, maybe we could help you find a simpler alternative.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5

    Default Re: QListWidget and takeItem() slow

    Thank you for taking the time to reply. I realized the code with clear() was incorrect, I meant that I didn't post the incorrect code? If that makes any sense

    Blocking the signals did the trick, I don't know why I didn't think to do that. I remember trying the disabling the updates which didn't do much difference. takeItem in that messy function I used before is much faster, but still too slow with updates and signals blocked. However, I wrote my own container for QListWidget with functions addItems and removeItems. Sadly, clearing the lists using take items, throwing everything in my container, calling removeItems and addItems, and then finally repopulating the lists based on my containers is infinitely faster.

    I have many lists in the program. Basically there is a left list, and a right list. You are able to select multiple items from one list and insert them into another. So all my QListWidgetItems are null parented and I think of the QListWidgets as more of containers, which is why I got frustrated when I realized clear() deleted my items.

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

    Default Re: QListWidget and takeItem() slow

    In my opinion you should use the model based approach. Preferably with the same base model for all views and two sort-filter proxies (one for each view) that would only hide or show respective entries from the base model.

    Here is a rough example implementation:
    Qt Code:
    1. #include <QtGui>
    2.  
    3. class Widget : public QWidget {
    4. Q_OBJECT
    5. public:
    6. enum {FilterRole = Qt::UserRole+1};
    7. Widget() {
    8. QHBoxLayout *l = new QHBoxLayout(this);
    9. lview = new QListView; rview = new QListView;
    10. l->addWidget(lview); l->addWidget(rview);
    11. model->setColumnCount(1);
    12. for(int i=0;i<100;i++){
    13. QStandardItem *item = new QStandardItem(QString::number(i+1));
    14. item->setData(true, FilterRole);
    15. item->setFlags(Qt::ItemIsEnabled); // disable editing
    16. model->appendRow(item);
    17. }
    18.  
    19. lproxy->setDynamicSortFilter(true);
    20. lproxy->setFilterRole(FilterRole);
    21. lproxy->setFilterFixedString("true");
    22. lproxy->setSourceModel(model);
    23. lview->setModel(lproxy);
    24.  
    25. rproxy->setDynamicSortFilter(true);
    26. rproxy->setFilterRole(FilterRole);
    27. rproxy->setFilterFixedString("false");
    28. rproxy->setSourceModel(model);
    29. rview->setModel(rproxy);
    30. connect(lview, SIGNAL(doubleClicked(QModelIndex)), SLOT(toggleItem(QModelIndex)));
    31. connect(rview, SIGNAL(doubleClicked(QModelIndex)), SLOT(toggleItem(QModelIndex)));
    32. }
    33. public slots:
    34. void toggleItem(const QModelIndex &index){
    35. bool isInLeft = index.data(FilterRole).toBool();
    36. const_cast<QAbstractItemModel*>(index.model())->setData(index, !isInLeft, FilterRole);
    37. }
    38. private:
    39. QListView *lview, *rview;
    40. };
    41.  
    42. #include "main.moc"
    43.  
    44. int main(int argc, char **argv){
    45. QApplication app(argc, argv);
    46. Widget w;
    47. w.show();
    48. return app.exec();
    49. }
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    neuronet (4th August 2014)

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
  •  
Qt is a trademark of The Qt Company.