Qt中的模拟QTabelWidget来处理大数据的显示

2019-07-13 08:59发布

http://blog.sina.com.cn/s/blog_a21fafc20102v2cp.html
在使用QTableWidget的时候,如果显示很多条数据,在1K条数据以上,就会感觉有点慢了,如果1W、10W、100W条数据在QTableWidget中显示,那显示速度可想而知;重新封装了一个类,来继承QTableWidget,主要使用延迟显示的方法将数据显示出来;        在tabelWidget中显示通过滚动条来控制显示,由于一屏幕中显示的数据是很少的,这样只将看见的数据显示在界面中,不看见的数据保存到内存中,只有拖到滚动条的时候在去加载这个表格中看到的数据,这样就将大数据分多次显示,如果数据超过100W以上就耗内存了,正所谓是空间换时间吧,没有真正的两全其美的事情,只有看自己写的程序更靠拢哪边,在根据具体情况而定;BigTableWidget类的头文件:///这个类来保存每一个Item的信息class BigTableWidgetInfo{public:BigTableWidgetInfo(){};~BigTableWidgetInfo(){};int nRow;  //!插入数据所在行数int nColumn;//!插入数据所在列数char strText[100]; //!在单元格中显示的数据QVariant userData; //!单元格中用户关联的数据};class BigTableWidget: public QTableWidget{Q_OBJECT
public:BigTableWidget(QWidget *parent = 0);~BigTableWidget();//!向表格中指定的行列添加显示信息和用户数据void addItem(int row,int column,QString strText,Qvariant userdata=NULL);//!初始化表格的行数和列数void initTabelRowAndColum(int row,int nColum);//!清除表格中的数据,启动一个线程在后台去处理数据的清除操作,不影响界面的操作void clearTableData();//!获取当前表格窗口显示最大的行数int getMaxCount(){return m_nMaxCount;}//!将数据保存到list的列表中void pushData(int row,int column,QString strText,,Qvariant userdata);protected:static void dealClearData(void* users);
private slots:void dealChangeValue(int nValue);private:Ui::BigTableWidget ui;int m_nMaxCount; //!每页显示的最大行数QList<BigTableWidgetInfo*> m_listTableInfo;  //!显示数据的存储列表QList<BigTableWidgetInfo*> m_listCopyTableInfo;//!存储清除数据的垃圾列表QMutex   m_tableInfoMutex;};      BigTableWidget类实现的代码如下:BigTableWidget::BigTableWidget(QWidget *parent) : QTableWidget(parent){ui.setupUi(this);///设置单元格为禁止编辑setEditTriggers(QAbstractItemView::NoEditTriggers);}/// 初始化表格的行数和列数void BigTableWidget::initTabelRowAndColum(int row,int nColum){this->setColumnCount(nColum);this->setRowCount(row);
    ///初始化窗口滚动条拖动变化的信号槽,以及窗口最多显示数据的行数QScrollBar* pBar = this->verticalScrollBar();connect((QObject*)pBar,SIGNAL(valueChanged(int)),this,SLOT(dealChangeValue(int)));int nRowHeight = this->rowHeight(0); int nScrollBarHeight=this->maximumViewportSize().height();//!获取滚动条的滚动范围m_nMaxCount = nScrollBarHeight/nRowHeight+1;}///这个是最重要的槽函数,拖动滚动条来动态的加载数据显示void BigTableWidget::dealChangeValue( int nValue ){int nRealRow = nValue;int nRowChanged=0;int nTempColum=this->columnCount();int nListSize = m_listTableInfo.size()/(nTempColum);//!滚动条拖动的数值但数据没有加载完成if(nValue>nListSize){QScrollBar* pBar = this->verticalScrollBar();pBar->setValue(nListSize);return;}if(nListSize-nRealRow < m_nMaxCount){nRowChanged = nListSize-nRealRow;}for(int i=0;i{if(i == nRowChanged && i+nRealRow == this->rowCount()){break;}for(int j=0;j{int temp = (i+nRealRow)*(nTempColum)+j;if(temp>=m_listTableInfo.size()){return;}BigTableWidgetInfo* info = m_listTableInfo.at(temp);QTableWidgetItem* tempitem = new QTableWidgetItem(QString::fromStdString(info->strText));tempitem->setTextAlignment(Qt::AlignHCenter);this->setItem(info->nRow,info->nColumn,tempitem);}}}///向看到的表格中加载显示数据void BigTableWidget::addItem( int row,int column,QString strText,QVariant  pUserData){MITSTableWigetInfo* info=new BigTableWidgetInfo;info->nRow= row;info->nColumn=column;strcpy(info->strText,strText.toStdString().c_str());info->userData=pUserData;m_listTableInfo.push_back(info);///m_nMaxCount在看到的区域内最多显示的记录条数if(row{QTableWidgetItem* tempitem = new QTableWidgetItem(strText);tempitem->setTextAlignment(Qt::AlignHCenter);this->setItem(row,column,tempitem);}}///如果没有在表格中显示的则存储到内存中void BigTableWidget::pushData(int row,int column,QString strText,QVariant pUserData){BigTableWidget Info* info=new BigTableWidgetInfo;info->nRow= row;info->nColumn=column;strcpy(info->strText,strText.toStdString().c_str());info->userData=pUserData;
m_listTableInfo.push_back(info);}
///如果很多条数据,在不用的时候将表格清空,并且要将内存中的数据清除,否则会占用内存;///考虑到10W以上数据的清除时在delete内存中的指针时是比较费时的,所以在清空表格以后将list中的数据放到一个线程中去慢慢的清除(在后台清除,不影响界面的操作)void BigTableWidget::clearTableData(){if(m_listTableInfo.isEmpty())return;m_listCopyTableInfo.append(m_listTableInfo);QMutexLocker locker(&m_tableInfoMutex);m_listTableInfo.clear();this->clearContents();this->setRowCount(1);QtConcurrent::run(dealClearData,(void*)this);}

///线程函数  清除历史数据void BigTableWidget::dealClearData( void* users ){BigTableWidget* pThis = static_cast<BigTableWidget*>(users);for(int i=0;im_listCopyTableInfo.size();++i){if(pThis->m_listCopyTableInfo.at(i))delete pThis->m_listCopyTableInfo.at(i);}pThis->m_listCopyTableInfo.clear();}
上边的就是一个简单的实现方法,如果进行排序,这种保存的数据结构在排序时就比较费时了,需要换一种数据结构进行保存,来保证数据的排序;因为这种数据结构是保存的每一个Item的数据,如果对某一行进行排序,需要调换改行的所有Item的顺序,并且要将Item中保存的row和column进行修改;以后有时间对排序的方法进行总结;