qtableview及自定义model的使用,对比qtablewidget性能及内存优化(转)
Published on 2023-02-05 12:05 in 分类: Qt with 萧海~
分类: Qt

qtableview及自定义model的使用,对比qtablewidget性能及内存优化(转)

    以前一直使用qtableiwdget,最近有时间来研究下qtableview,才知道,qtableview和自定义model,比qtablewidget的性能啊,及占用内存啊,优化太多了。以前我使用qtablewidget是进行动态加载,也可以对内存进行优化,但是前提是,你只看数据,不对数据进行操作。
    先看一张对比图。我打开了大概10万条数据。
    qtablewidget

    在这里插入图片描述
    可以看到占用内存400mb左右,操作起来轻微卡顿。我试过加载100万条数据,加载时候要等上几分钟,然后操作就卡的要死,内存爆到2个多g

    然后看下qtableview和自定义model。
    在这里插入图片描述
    内存已经降到123mb,这个优化基本在1.5倍左右,加载100万数据的时候,大概占用750mb左右,操作流畅。

    下面直接看model
    qtableview使用自定义的model,需要继承QAbstractTableModel,需要实现3个纯虚函数rowcount,columncount,data,这3个是必须的。其他的纯虚函数根据需要进行实现,我是实现了删除功能(全选删除,按住ctrl删除),获取数据功能,以及设置数据功能。根据自己需求来吧,目前我只需要这么多。
    直接看model代码吧

    #ifndef MYTABLEMODEL_H
    #define MYTABLEMODEL_H
    #include <QWidget>
    #include <QAbstractTableModel>
    struct ModelItem {
    QString id;
    QString name;
    QString one;
    QString two;
    QString three;
    QString four;
    QString five;
    QString six;
    };
    class MyTableModel : public QAbstractTableModel
    {
    Q_OBJECT
    public:
    explicit MyTableModel(QObject *parent = nullptr);
    ~MyTableModel();
    int rowCount(const QModelIndex &parent = QModelIndex())const override;
    int columnCount(const QModelIndex &parent = QModelIndex())const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole)const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    //bool insertRows(int row, int count,const QModelIndex &parent = QModelIndex());
    virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
    void SetDeleteList(QList<int> i_List);
    void SetHeadData(QStringList i_list);
    void SetModelData(QList<ModelItem> model);
    signals:
    private:
    QList<ModelItem> modelData;
    QStringList headeList;
    QList<int> m_DeleteList;
    };
    #endif // MYTABLEMODEL_H
    #include "mytablemodel.h"
    #include <qdebug.h>
    #include <QElapsedTimer>
    MyTableModel::MyTableModel(QObject *parent)
    {
    }
    MyTableModel::~MyTableModel()
    {
    }
    int MyTableModel::rowCount(const QModelIndex &parent) const
    {
    return modelData.count();
    }
    int MyTableModel::columnCount(const QModelIndex &parent) const
    {
    return headeList.size();
    }
    QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
    {
    if (section < headeList.size())
    {
    return headeList[section];
    }
    }
    return QAbstractItemModel::headerData(section, orientation, role);
    }
    bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if(!index.isValid())
    return 0;
    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
    const int row=index.row();
    switch(index.column())
    {
    case 0: modelData[row].id=value.toString();break;
    case 1:modelData[row].name=value.toString();break;
    case 2:modelData[row].one=value.toString();break;
    case 3:modelData[row].two=value.toString();break;
    case 4:modelData[row].three=value.toString();break;
    case 5:modelData[row].four=value.toString();break;
    case 6:modelData[row].five=value.toString();break;
    case 7:modelData[row].six=value.toString();break;
    }
    emit dataChanged(index, index, QVector<int>() << role);
    return true;
    }
    return false;
    }
    //bool MyTableModel::insertRows(int row, int count,const QModelIndex &parent)
    //{
    if(row<0||count<1||row>rowCount())
    return false;
    //需要将操作放到beginInsertRows和endInsertRows两个函数调用之间
    beginInsertRows(parent, row, row + count - 1);
    for(int i=row;i<row+count;i++)
    {
    //在接口对应行插入空数据
    modelData.insert(i,ModelItem);
    }
    endInsertRows();
    // // return true;
    //}
    bool MyTableModel::removeRows(int row, int count, const QModelIndex &parent)
    {
    if(row<0||count<1||row+count>rowCount())
    return false;
    //需要将操作放到beginRemoveRows和endRemoveRows两个函数调用之间
    beginRemoveRows(parent, row, row + count - 1);
    if(m_DeleteList.size()!=0)
    {
    for(int i=0;i<m_DeleteList.size();i++)
    {
    modelData.removeAt(m_DeleteList[i]);
    }
    }
    // for(int i=row+count-1;i>=row;i--)
    // {
    // //移除该行数据
    // modelData.removeAt(i);
    // }
    m_DeleteList.clear();
    endRemoveRows();
    return true;
    }
    void MyTableModel::SetDeleteList(QList<int> i_List)
    {
    m_DeleteList=i_List;
    }
    QVariant MyTableModel::data(const QModelIndex &index, int role) const
    {
    if(!index.isValid())
    return QVariant();
    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
    const int row=index.row();
    switch(index.column())
    {
    case 0: return modelData.at(row).id;
    case 1:return modelData.at(row).name;
    case 2:return modelData.at(row).one;
    case 3:return modelData.at(row).two;
    case 4:return modelData.at(row).three;
    case 5:return modelData.at(row).four;
    case 6:return modelData.at(row).five;
    case 7:return modelData.at(row).six;
    }
    }
    return QVariant();
    }
    void MyTableModel::SetHeadData(QStringList i_list)
    {
    headeList=i_list;
    }
    void MyTableModel::SetModelData(QList<ModelItem> model)
    {
    modelData=model;
    }

    widget

    #ifndef WIDGET_H
    #define WIDGET_H
    #include <QWidget>
    #include <QTableView>
    #include "mytablemodel.h"
    #include <QMenu>
    class Widget : public QWidget
    {
    Q_OBJECT
    public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void InitViewAction();
    public slots:
    void onShotListContextMenuClicked();
    void onImportTriggered();
    void onDeleteTriggered();
    void onDeleteALLTriggered();
    private:
    QTableView *m_pTableView=nullptr;
    MyTableModel *m_pModel=nullptr;
    QMenu *m_pMenu=nullptr;
    };
    #endif // WIDGET_H
    #include "widget.h"
    #include <qgridlayout.h>
    #include <QStandardItemModel>
    #include <qdebug.h>
    #include <QTableWidget>
    #include <qfile.h>
    #include <QAction>
    #include <qmenu.h>
    #include <QHeaderView>
    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    {
    this->resize(800,500);
    m_pTableView=new QTableView(this);
    QVBoxLayout *mainLayout=new QVBoxLayout(this);
    mainLayout->addWidget(m_pTableView);
    mainLayout->setMargin(0);
    mainLayout->setSpacing(0);
    this->setLayout(mainLayout);
    InitViewAction();
    m_pTableView->setSelectionBehavior(QAbstractItemView::SelectRows); //选中整行
    //m_pTableView->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(m_pTableView, &QTableView::customContextMenuRequested, this, &Widget::onShotListContextMenuClicked);
    QStringList strList;
    strList<<QString("ID")<<"Name"<<"one"<<"two"<<"three"<<"four"<<"five"<<"six";
    m_pModel=new MyTableModel();
    m_pModel->SetHeadData(strList);
    m_pTableView->setModel(m_pModel);
    m_pTableView->verticalHeader()->hide();
    QList<ModelItem> modelData;
    QFile file("C:/Users/dujia/Desktop/bbb.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    return;
    while (!file.atEnd()) {
    QString strLine=file.readLine();
    QStringList strList=strLine.split("&");
    if(strList.size()<7)
    {
    continue;
    }
    ModelItem item;
    item.id=strList[0];
    item.name=strList[1];
    item.one=strList[2];
    item.two=strList[3];
    item.three=strList[4];
    item.four=strList[5];
    item.five=strList[6];
    item.six="";
    modelData.append(item);
    }
    m_pModel->SetModelData(modelData);
    // QTableWidget *widget=new QTableWidget(this);
    // //widget->setRowCount(1000000);
    // widget->setColumnCount(8);
    // QStringList strList;
    // strList<<QString("ID")<<"Name"<<"one"<<"two"<<"three"<<"four"<<"five";
    // widget->setHorizontalHeaderLabels(strList);
    // QVBoxLayout *mainLayout=new QVBoxLayout(this);
    // mainLayout->addWidget(widget);
    // mainLayout->setMargin(0);
    // mainLayout->setSpacing(0);
    // this->setLayout(mainLayout);
    // QFile file("C:/Users/dujia/Desktop/bbb.txt");
    // if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    // return;
    // int i=0;
    // widget->setRowCount(100000);
    // while (!file.atEnd()) {
    // QString strLine=file.readLine();
    // QStringList strList=strLine.split("&");
    // if(strList.size()<8)
    // {
    // continue;
    // }
    // widget->setItem(i,0,new QTableWidgetItem(strList[0]));
    // widget->setItem(i,1,new QTableWidgetItem(strList[1]));
    // widget->setItem(i,2,new QTableWidgetItem(strList[2]));
    // widget->setItem(i,3,new QTableWidgetItem(strList[3]));
    // widget->setItem(i,4,new QTableWidgetItem(strList[4]));
    // widget->setItem(i,5,new QTableWidgetItem(strList[5]));
    // widget->setItem(i,6,new QTableWidgetItem(strList[6]));
    // widget->setItem(i,7,new QTableWidgetItem(strList[7]));
    // i++;
    // }
    }
    Widget::~Widget()
    {
    }
    void Widget::InitViewAction()
    {
    m_pMenu = new QMenu(this);
    QAction *qcOnlyAction = new QAction(tr("QC only"), this);
    QAction *submitJobAction = new QAction(tr("Generate SEGD"), this);
    //QAction *killAllJobAction = new QAction(tr("Kill all jobs"), this);
    QAction *commentsAction = new QAction(tr("Comments..."), this);
    QAction *deleteAction = new QAction(tr("Delete..."), this);
    QAction *importAction = new QAction(tr("Import Shot Data"), this);
    QAction *allAction = new QAction(tr("All"), this);
    QAction *returnAction = new QAction(tr("Return"), this);
    m_pMenu->addSeparator();
    m_pMenu->addAction(importAction);
    m_pMenu->addSeparator();
    m_pMenu->addAction(qcOnlyAction);
    m_pMenu->addAction(submitJobAction);
    m_pMenu->addSeparator();
    m_pMenu->addSeparator();
    m_pMenu->addAction(deleteAction);
    m_pMenu->addSeparator();
    m_pMenu->addAction(allAction);
    m_pMenu->addAction(returnAction);
    m_pMenu->addSeparator();
    m_pMenu->addAction(commentsAction);
    m_pMenu->addSeparator();
    m_pMenu->hide();
    connect(importAction,&QAction::triggered,this,&Widget::onImportTriggered);
    connect(deleteAction,&QAction::triggered,this,&Widget::onDeleteTriggered);
    connect(allAction,&QAction::triggered,this,&Widget::onDeleteALLTriggered);
    }
    void Widget::onShotListContextMenuClicked()
    {
    m_pMenu->move(QCursor::pos());
    m_pMenu->show();
    }
    void Widget::onImportTriggered()
    {
    QItemSelectionModel *selections = m_pTableView->selectionModel();
    QModelIndexList selected = selections->selectedIndexes();
    QList<int> rowList;
    QMap<int, int> rowMap;
    foreach (QModelIndex index, selected)
    {
    rowMap.insert(index.row(), 0);
    }
    int rowToDel;
    QMapIterator<int, int> rowMapIterator(rowMap);
    while (rowMapIterator.hasNext())
    {
    rowMapIterator.next();
    rowToDel = rowMapIterator.key();
    QModelIndex indexsix = m_pModel->index(rowToDel,7);
    m_pModel->setData(indexsix,"hello");
    }
    }
    #include <QElapsedTimer>
    void Widget::onDeleteTriggered()
    {
    QItemSelectionModel *selections = m_pTableView->selectionModel();
    QModelIndexList selected = selections->selectedIndexes();
    QList<int> rowList;
    QMap<int, int> rowMap;
    foreach (QModelIndex index, selected)
    {
    rowMap.insert(index.row(), 0);
    }
    int rowToDel;
    QMapIterator<int, int> rowMapIterator(rowMap);
    rowMapIterator.toBack(); //将迭代器移动到最后
    while (rowMapIterator.hasPrevious())
    {
    rowMapIterator.previous();
    rowToDel = rowMapIterator.key();
    rowList.append(rowToDel);
    }
    m_pModel->SetDeleteList(rowList); //传入需要删除的数组
    m_pModel->removeRows(rowList.last(),rowList.size());
    m_pTableView->setCurrentIndex(QModelIndex()); //设置当前项为不存在的项,则为不选中
    }
    void Widget::onDeleteALLTriggered()
    {
    int count=m_pModel->rowCount();
    m_pModel->removeRows(0,count);
    }

    数据:

    1512058602& 2884.00& 12010.00 &1&G1& 644347.8& 4229422.2&3123.7&38 12 04.281 N&076 38 54.825 E&3123.70& & &&
    1512058603& 2884.00& 12011.00 &1&G1& 644357.8& 4229439.4&3123.8&38 12 04.833 N&076 38 55.249 E&3123.80& & &&
    1512058604& 2884.00& 12012.00 &1&G1& 644367.7& 4229456.9&3123.1&38 12 05.395 N&076 38 55.669 E&3123.10& & &&
    1512058605& 2884.00& 12013.00 &1&G1& 644377.8& 4229474.1&3124.3&38 12 05.947 N&076 38 56.096 E&3124.30& & &&

    https://blog.csdn.net/weixin_43676892/article/details/115998997?spm=1001.2014.3001.5502

    posted @   萧海~  阅读(941)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
    · AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
    · 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
    · Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
    · 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
    历史上的今天:
    2021-02-05 Qt QComboBox 自动查找匹配项功能实现
    2021-02-05 Qt QComboBox+QCompleter实现搜索自动匹配
    2021-02-05 Qt QLineEdit、QCombox、QCompleter 实现模糊搜索
    2021-02-05 Windows CMD命令大全
    2021-02-05 Excel后缀.xls和.xlsx有什么区别
    2021-02-05 C++11用两个线程轮流打印整数
    2021-02-05 Qt 3D入门(二)
    点击右上角即可分享
    微信分享提示
    电磁波切换