求教: QTableView 模型内数据变化导致移除慢

王桑的一天 2019-07-04 02:33:20

class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setWindowTitle("Test")
self._layout = QVBoxLayout(self)
self._layout.setAlignment(Qt.AlignLeft)
self.table = QTableView(self)
self.table.setSortingEnabled(True)
self.model = QStandardItemModel(self)

colCount = 46
for i in range(10000):
# 后 5000 行有70列
if i > 5000:
colCount = 70
lst = [QStandardItem('Test %s,%s' % (i, j)) for j in range(colCount)]
self.model.appendRow(lst)

sortProxy = QSortFilterProxyModel(self)
sortProxy.setSourceModel(self.model)
self.table.setModel(sortProxy)

btLayout = QHBoxLayout()
deleteBt = QPushButton(self)
deleteBt.setText('Delete All')
delete10 = QPushButton(self)
delete10.setText('Delete 10 rows')
deleteBt.clicked.connect(self.deleteRows)
delete10.clicked.connect(self.delete10Rows)
self._layout.addWidget(self.table)
self._layout.addLayout(btLayout)
btLayout.addWidget(deleteBt)
btLayout.addWidget(delete10)
btLayout.addStretch()

def delete10Rows(self):
self.table.model().removeRows(10, 10)

# 如果列数全部相同,不删除10行,直接选中删除全部行要2秒
# 如果列数全部相同,先删除10行,再选中删除全部行要 无穷 秒。。
# 如果列数不同,全部选中删除要70秒
def deleteRows(self):
selectModel = self.table.selectionModel()
selectedRows = selectModel.selectedRows()
if len(selectedRows) == 0:
return

selectedRows.sort(key=lambda x: x.row(), reverse=True)
for index in selectedRows:
self.table.model().removeRow(index.row())

if __name__ == '__main__':
app = QApplication(sys.argv)
main = Dialog()
main.show()
sys.exit(app.exec_())


为什么会这么慢呢?
...全文
3166 23 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
走好每一步 2019-07-09
  • 打赏
  • 举报
回复
引用 23 楼 管理員 的回复:
使用自定义模型解决了,速度极大提升,内存占用极大减少。 但是这个问题的原因,仍然不明。。。
VS2017 + QT静态编译版本,想怎么单步都可以。
王桑的一天 2019-07-09
  • 打赏
  • 举报
回复
使用自定义模型解决了,速度极大提升,内存占用极大减少。 但是这个问题的原因,仍然不明。。。
走好每一步 2019-07-06
  • 打赏
  • 举报
回复
还有另外一种办法,自定义model,
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
重载这个函数,自己写。
走好每一步 2019-07-06
  • 打赏
  • 举报
回复
引用 17 楼 管理員 的回复:
花猜测也没有什么用,QT遇到问题,我都直接看源码了。

一言不和就看源码吗? 帮我看看呗,我看不懂[/quote]

难道还有什么办法比这个更快捷么。。。
而且QT这么优秀的库。
走好每一步 2019-07-06
  • 打赏
  • 举报
回复
引用 20 楼 Vcat7 的回复:
是为了删除选中行,后面为了方面又去掉了,没删干净。 你是先点按钮删除 10行,再删除所有行? 不慢吗? 我是 5.12.1
5.9.1 不慢的,就花了5.18秒。
Vcat7 2019-07-06
  • 打赏
  • 举报
回复
是为了删除选中行,后面为了方面又去掉了,没删干净。 你是先点按钮删除 10行,再删除所有行? 不慢吗? 我是 5.12.1
王桑的一天 2019-07-05
  • 打赏
  • 举报
回复
这个问题没人知道吗.... 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;
    for(auto i = 0; i < 10000; i++)
    {
        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);
}

// 先删除 10行,再删除所有,会非常慢
void MainWindow::deleteAllRows()
{

    auto selectionModel = tableView->selectionModel();
    auto selectedRows = selectionModel->selectedRows();
    if (selectedRows.size() == 0)
        return;

    for(auto row = tableModel->rowCount(); row >= 0; --row)
    {
        tableModel->removeRow(row);
    }
}

走好每一步 2019-07-05
  • 打赏
  • 举报
回复
引用 4 楼 管理員 的回复:
[quote=引用 2 楼 走好每一步 的回复:] 还有楼主既然选择搞QT,可以考虑下学C++。 python是脚本语言,单靠它,就业面有点窄。 C java c++ python
你说的没错,我在学。但新手机会还是少的[/quote] c++比较难学,因为c++的那帮人自命不凡,不跟读者说人话。 其实找对路了,学起来也很快。 学习Java,要学得深也需要懂C++ c比较容易学得。 不过你从脚本切到这些语言都不容易, 语言有几大类: 面向过程 面向对象 脚本 函数式
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
引用 3 楼 管理員 的回复:
[quote=引用 1 楼 走好每一步 的回复:] [quote=引用 楼主 管理員 的回复:]

class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowTitle("Test")
        self._layout = QVBoxLayout(self)
        self._layout.setAlignment(Qt.AlignLeft)
        self.table = QTableView(self)
        self.table.setSortingEnabled(True)
        self.model = QStandardItemModel(self)

        colCount = 46
        for i in range(10000):
            # 后 5000 行有70列
            if i > 5000:     
                colCount = 70
            lst = [QStandardItem('Test %s,%s' % (i, j)) for j in range(colCount)]
            self.model.appendRow(lst)

        sortProxy = QSortFilterProxyModel(self)
        sortProxy.setSourceModel(self.model)
        self.table.setModel(sortProxy)

        btLayout = QHBoxLayout()
        deleteBt = QPushButton(self)
        deleteBt.setText('Delete All')
        delete10 = QPushButton(self)
        delete10.setText('Delete 10 rows')
        deleteBt.clicked.connect(self.deleteRows)
        delete10.clicked.connect(self.delete10Rows)
        self._layout.addWidget(self.table)
        self._layout.addLayout(btLayout)
        btLayout.addWidget(deleteBt)
        btLayout.addWidget(delete10)
        btLayout.addStretch()

    def delete10Rows(self):
        self.table.model().removeRows(10, 10)

    # 如果列数全部相同,不删除10行,直接选中删除全部行要2秒
    # 如果列数全部相同,先删除10行,再选中删除全部行要 无穷 秒。。
    # 如果列数不同,全部选中删除要70秒
    def deleteRows(self):
        selectModel = self.table.selectionModel()
        selectedRows = selectModel.selectedRows()
        if len(selectedRows) == 0:
            return

        selectedRows.sort(key=lambda x: x.row(), reverse=True)
        for index in selectedRows:
            self.table.model().removeRow(index.row())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Dialog()
    main.show()
    sys.exit(app.exec_())
为什么会这么慢呢?
一般删除是从尾端开始删,没有从头部开始删的。[/quote] 我是从尾部开始删的,注意看我把选中的行号逆序了 [/quote] 那你换成头部开始删除,这个主要是看底部源码的实现。 如果是动态数组,尾端删除效率高。 如果是链表,从头部开始删除效率高
王桑的一天 2019-07-05
  • 打赏
  • 举报
回复
引用 16 楼 走好每一步 的回复:
猜测也没有什么用,QT遇到问题,我都直接看源码了。

一言不和就看源码吗? 帮我看看呗,我看不懂
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
猜测也没有什么用,QT遇到问题,我都直接看源码了。
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
搞个static版本的QT,源码都可以进去看的
王桑的一天 2019-07-05
  • 打赏
  • 举报
回复
引用 13 楼 走好每一步 的回复:
auto row = tableModel->rowCount();
就是说如果row从0开始,你这里需要-1


不是这个的问题。只要先删10行,再全删,就会慢。直接全删我这边也快的,1秒的样子。
或者所有行的列数不一样,删除也会慢
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
auto row = tableModel->rowCount(); 就是说如果row从0开始,你这里需要-1
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
auto row = tableModel->rowCount(); 你注意下这里,row下标是否从0开始
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
是的,1秒左右就能删完了。 我觉得这么大的数据量,能接受了。
王桑的一天 2019-07-05
  • 打赏
  • 举报
回复
列数不一致也会很慢

#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

#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;
    for(auto i = 0; i < 10000; i++)
    {
        if (i > 5000)
            col = 70;  //后 5000 行 70列
        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);
}

void MainWindow::deleteAllRows()
{
    for(auto row = tableModel->rowCount(); row >= 0;)
    {
        tableModel->removeRow(--row);
    }
}

王桑的一天 2019-07-05
  • 打赏
  • 举报
回复
引用 8 楼 走好每一步 的回复:
[quote=引用 7 楼 管理員 的回复:] [/code]
试了,不会慢,我用的是QT5.9.1. 我不知道你删除所有,为啥要选一下才给删。[/quote] 是为了删除选中行,后面为了方面又去掉了,没删干净。 你是先点按钮删除 10行,再删除所有行? 不慢吗? 我是 5.12.1
走好每一步 2019-07-05
  • 打赏
  • 举报
回复
引用 7 楼 管理員 的回复:
这个问题没人知道吗.... 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;
    for(auto i = 0; i < 10000; i++)
    {
        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);
}

// 先删除 10行,再删除所有,会非常慢
void MainWindow::deleteAllRows()
{

    auto selectionModel = tableView->selectionModel();
    auto selectedRows = selectionModel->selectedRows();
    if (selectedRows.size() == 0)
        return;

    for(auto row = tableModel->rowCount(); row >= 0; --row)
    {
        tableModel->removeRow(row);
    }
}

试了,不会慢,我用的是QT5.9.1. 我不知道你删除所有,为啥要选一下才给删。
王桑的一天 2019-07-04
  • 打赏
  • 举报
回复
引用 2 楼 走好每一步 的回复:
还有楼主既然选择搞QT,可以考虑下学C++。
python是脚本语言,单靠它,就业面有点窄。

C
java
c++
python

你说的没错,我在学。但新手机会还是少的
加载更多回复(3)

16,817

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧