It's extremely slow to remove all rows from QTableView.



  • mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QDialog>
    #include <QTableView>
    #include <QVBoxLayout>
    #include <QStandardItemModel>
    #include <QPushButton>
    
    
    class MainWindow : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        QTableView *tableView;
        QVBoxLayout *mainLayout;
        QStandardItemModel *tableModel;
        QHBoxLayout *btLayout;
        QPushButton *deleteAllBt;
        QPushButton *delete10;
    
        ~MainWindow();
    
    
    private:
        int col;
        void retranslateUi();
    
    private slots:
        void delete10Rows();
        void deleteAllRows();
    };
    
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QDialog(parent)
    {
        tableView = new QTableView;
        tableModel = new QStandardItemModel;
        mainLayout = new QVBoxLayout;
        btLayout = new QHBoxLayout;
        delete10 = new QPushButton;
        deleteAllBt = new QPushButton;
    
        tableView->setAttribute(Qt::WA_DeleteOnClose);
        tableView->setSortingEnabled(true);
        tableView->setModel(tableModel);
    
        btLayout->addWidget(delete10);
        btLayout->addWidget(deleteAllBt);
        btLayout->addStretch();
    
        mainLayout->addWidget(tableView);
        mainLayout->addLayout(btLayout);
        setLayout(mainLayout);
    
    
        connect(delete10, SIGNAL(clicked()), this, SLOT(delete10Rows()));
        connect(deleteAllBt, SIGNAL(clicked()), this, SLOT(deleteAllRows()));
    
        retranslateUi();
        resize(QSize(600, 480));
    
        col = 46;  // column count
        for(auto i = 0; i < 10000; i++)
        {
            if (i > 5000)
                col = 70;  //change column count 
            QList<QStandardItem *> items;
            for(auto j = 0; j < col; j++)
            {
                items.append(new QStandardItem(tr("Test %1 x %2").arg(i).arg(j)));
            }
            tableModel->appendRow(items);
        }
    }
    
    MainWindow::~MainWindow()
    {
    
    }
    
    void MainWindow::retranslateUi()
    {
        setWindowTitle(tr("Test"));
        delete10->setText(tr("Delete 10 Rows"));
        deleteAllBt->setText(tr("Delete All"));
    }
    
    void MainWindow::delete10Rows()
    {
        tableModel->removeRows(10, 10);
    }
    
    // it's extremely slow to remove all rows
    void MainWindow::deleteAllRows()
    {
        for(auto row = tableModel->rowCount(); row >= 0;)
        {
            tableModel->removeRow(--row);
        }
    //    tableModel->removeRows(0, tableModel->rowCount());
    }
    
    


  • @Sungsong

    • removeRows() should be faster ---or at least no worse --- than removeRow() one at a time. If it isn't, that's worrying. See e.g. https://www.qtcentre.org/threads/65616-Slow-performance-Removing-huge-amount-of-rows-from-qstandarditemmodel.

    • Make sure beginRemoveRows() gets called once for multiple rows. Verify that your QStandardItemModel does this for you, because I can't actually see that overrides the base QAbstractItemModel::beginRemoveRows(), which does nothing?

    • You have tableView->setSortingEnabled(true);. Try switching that off, at least for the removal, because if the model resorts after each removal it may be slow. Does that make any difference to speed? Even try detaching your view from the model for the duration of the delete and then re-attach at the end? Does that make a significant difference? You need to identify whether its the model or the view which is being "slow" (e.g. view is being updated all the time), and then create solution from there.

    Also, you do not bother to tell us how many rows your "all rows" is? Maybe it's 100,000+? QStandardItemModel is not recommended for "large" numbers of rows (reference: https://www.qtcentre.org/threads/55864-QStandardItemModel-performance-with-high-number-of-elements?p=249783#post249783, and read the other posts if this is your situation).


  • Lifetime Qt Champion

    Hi,

    If you want to empty your model, why not use the clear method ?



  • @SGaist
    What's really annoying is that I explicitly searched doc page for a clear() method and got no matches, even though I now see it from your link (I obviously did something wrong) :(

    Of course that does not address if the OP needs to delete, say, all-but-one-row and is finding that too slow, so he still probably wants to address removeRows() speed...


  • Qt Champions 2018

    @SGaist said in It's extremely slow to remove all rows from QTableView.:

    If you want to empty your model, why not use the clear method ?

    Clear also removes the headers.
    +1 for using removeRows



  • @JonB said in It's extremely slow to remove all rows from QTableView.:

    @Sungsong

    • removeRows() should be faster ---or at least no worse --- than removeRow() one at a time. If it isn't, that's worrying. See e.g. https://www.qtcentre.org/threads/65616-Slow-performance-Removing-huge-amount-of-rows-from-qstandarditemmodel.

    • Make sure beginRemoveRows() gets called once for multiple rows. Verify that your QStandardItemModel does this for you, because I can't actually see that overrides the base QAbstractItemModel::beginRemoveRows(), which does nothing?

    • You have tableView->setSortingEnabled(true);. Try switching that off, at least for the removal, because if the model resorts after each removal it may be slow. Does that make any difference to speed? Even try detaching your view from the model for the duration of the delete and then re-attach at the end? Does that make a significant difference? You need to identify whether its the model or the view which is being "slow" (e.g. view is being updated all the time), and then create solution from there.

    Also, you do not bother to tell us how many rows your "all rows" is? Maybe it's 100,000+? QStandardItemModel is not recommended for "large" numbers of rows (reference: https://www.qtcentre.org/threads/55864-QStandardItemModel-performance-with-high-number-of-elements?p=249783#post249783, and read the other posts if this is your situation).

    1. Because I just want to remove selected rows.
    2. Disable sorting doesn't help.

    The key point is: these rows have different column count . If they have same column count, it's fairly fast, even if I removeRow() one by one.



  • @VRonin @SGaist
    removeRows() and clear() doesn't help. The key point is: these rows have different column count.

    Another case:
    All rows have same column count.

    1. Remove 10 rows first.
    2. Remove all rows.

    The problem will also happen.



  • @Sungsong

    The key point is: these rows have different column count . If they have same column count, it's fairly fast, even if I removeRow() one by one.

    Do you think it would have helped us if you had drawn attention to this unusual situation (different column count) when you first pasted in your code with no comment/explanation at all? Or do you think it better we figure this for ourselves?



  • @JonB
    I added comments in my code. I think I should explain it clearly. Sorry... but please help.