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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源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入门(二)