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

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


可以看到占用内存400mb左右,操作起来轻微卡顿。我试过加载100万条数据,加载时候要等上几分钟,然后操作就卡的要死,内存爆到2个多g然后看下qtableview和自定义model。

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


内存已经降到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&    &    &&