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_OBJECTpublic: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& & &&
拿过去直接复制粘贴到txt就行了。
ヾ( ̄▽ ̄)ByeBye
qtableview及自定义model的使用,对比qtablewidget性能及内存优化相关推荐
- QTableView使用自定义委托(QItemDelegate)
QTableView使用自定义委托(QItemDelegate) 需要在表格中绘制流程图,主要有箭头,方向,颜色,字符串,由于QTableView没有可用的绘制函数,所以需要自己去定义. 委托(del ...
- 什么是php model类,thinkphp的自定义model类有什么作用?
请问,thinkphp的自定义model类有什么作用?如: <?php //自定义Modle类 namespace Home\Model; use Think\Model; class StuM ...
- [golang gin框架] 4.自定义Model以及Gin 文件上传
一.Gin 中自定义 Model 关于 Model 如果应用非常简单的话,我们可以在 Controller 里面处理常见的业务逻辑,但是如果 有一个功能想在多个控制器.或者多个模板里面复用的话,那么就 ...
- ML之DTRFRExtraTRGBR:基于四种算法(DT、RFR、ExtraTR、GBR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
ML之DT&RFR&ExtraTR&GBR:基于四种算法(DT.RFR.ExtraTR.GBR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自 ...
- 【Android 内存优化】自定义组件长图组件 ( 长图滚动区域解码 | 手势识别 GestureDetector | 滑动计算类 Scroller | 代码示例 )
文章目录 一.GestureDetector 创建与设置 二.GestureDetector 触摸事件传递 三.触摸滑动操作 四.惯性滑动操作 五.长图滑动组件代码示例 六.运行效果 七.源码及资源下 ...
- 【Android 内存优化】自定义组件长图组件 ( 获取图像宽高 | 计算解码区域 | 设置图像解码属性 复用 像素格式 | 图像绘制 )
文章目录 一.获取图像真实宽高 二.计算解码区域 三.设置解码参数 内存复用 像素格式 四.图像绘制 五.执行效果 六.源码及资源下载 官方文档 API : BitmapRegionDecoder 在 ...
- ML之kNN(两种):基于两种kNN(平均回归、加权回归)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
ML之kNN(两种):基于两种kNN(平均回归.加权回归)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能 目录 输出结果 设计思路 核心代码 输出结果 Bosto ...
- ML之SVM(三种):基于三种SVM(linearSVR、polySVR、RBFSVR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
ML之SVM(三种):基于三种SVM(linearSVR.polySVR.RBFSVR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能 目录 输出结果 设计思路 ...
- ML之LiRSGDR:基于二种算法(LiR、SGDR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能
ML之LiR&SGDR:基于二种算法(LiR.SGDR)对Boston(波士顿房价)数据集(506,13+1)进行价格回归预测并对比各自性能 目录 输出结果 设计思路 核心代码 输出结果 Bo ...
- EL之DTRFGBT:基于三种算法(DT、RF、GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能
EL之DT&RF&GBT:基于三种算法(DT.RF.GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能 目录 输出结果 设计思路 核心代码 输出结果 设计思路 核 ...
最新文章
- 斯坦福大学深度学习与自然语言处理第三讲:高级的词向量表示
- 一、flask的基本使用-flask
- IDA Pro ARM指令集和Thumb指令集的切换
- 我们工作到底为了什么(这篇文章很重要)----强烈推荐
- UART_SEND详细设计方案
- tcp通讯一次最多能发送多少数据?_关于TCP/IP,必须知道的十个知识点
- c#位数不够0补充完_Java与C#比较,哪个语言更是适合你?
- php页面审核,深入理解用PHP实现页面注册审核
- 论文编辑——插入公式编号并对齐、插入图表编号、正文引用各类编号
- 2023年陕西师范大学宗教学考研上岸前辈备考经验指导
- 知识图谱从0到-1的笔记——6.知识推理
- ps如何制作霓虹字体
- 系统性谈谈软件可靠性——第3讲:软件可靠性设计方法
- jee6 学习笔记 5 - Struggling with JSF2 binding GET params
- 大陆引进《火影忍者》角色中文译名雷人出炉
- js实现页面表格内容的复制粘贴填充,实现快速填写
- canvas 将两张图片叠加
- 45台计算机的网络拓扑图,网络复习习题
- url资源(html相关)
- 上海青浦区大众驾校(科目二·自动挡)真实考场操作全程
热门文章
- git学习笔记-(11-git存储)
- 怎么解Linux内核温控,Linux Thermal 框架解析
- mysql 一台电脑多个服务_怎么在一台windows主机上安装多个mysql服务
- android runnable传递参数,Android – 如何将数据传递到RunOnUiThread中的Runnable?
- java exception 级别_Java异常体系概述
- 事务方法调用事务方法_实现系统调用的几种方法
- linux系统怎么拨号上网,如何用 Linux 拨号上网
- oracle永久表设置,Oracle 表空间简单管理永久表空间
- cookie被淘汰_可爱可恨的 Cookie
- SpringBoot系列(7):SpringBoot启动流程源码分析()