在使用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;
}
BigTableWidget
Info* 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
BigTableWidget
Info;
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
BigTableWidget
Info;
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进行修改;
以后有时间对排序的方法进行总结;