以前一直使用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& & &&