qtablewidget解决加载百万条数据卡顿(不会存在内存溢出,界面也不会卡顿)动态加载

其实前面使用多线程进行写过一个动态加载,原先我自己以为没问题,但是后面看了下任务管理器,100万条数据后台加载到5个g还在激增。这样下去当内存超出一定范围,就会宕机,后来查看代码就发现这个机制是一直向你的表格中一直插入,并不会释放掉。后来,经过几天的沉淀,网上大部分说使用tableview以及自定model,效率比qtablewidget效率高。其实自定义的model无非就是后台处理数据,我给qtablewidget单独开出一条线程,也不会有任何卡顿。
下面来说下简易思路,然后配合代码细讲。
简单的思路:比如你有一个文件,里面有100万行数据,我们想将他加载到qtablewidget,qtablewidget加载100条,1000条数据都没啥问题。你不会有感觉卡顿什么的,但是当你加载到一万条数据以上,卡顿就会越来越明显,(重点来了),那该如何加载这100万条数据呢。首先一个窗体是有限的,也就是说,不论你将窗口放的再大,你也不可能同时看到100万条数据,其实有限的视野也就是同时看到100条左右。首先我们需要单独开出一个线程来进行加载100万条数据,目的是为了不卡住主界面,使用一个自定义结构体来存储你的数据,当我鼠标滚轮滚动的时候,(比如向下滚动滚轮,我就向下加载5条数据),但是我的界面始终只有100条数据,所以你的界面始终不会卡顿,内存也不会存在溢出的情况。
好,下面结合代码细说
我们先看自定义tablewidget:
构造:

connect(this->verticalScrollBar(),&QScrollBar::valueChanged,this,&MyTableWgt::OnVertivalValueChanged);
    m_pDeal= new MyDeal();

    m_pDeal->moveToThread(&m_thread);
    connect(this,&MyTableWgt::startRunning,m_pDeal,&MyDeal::CreateData);
    connect(&m_thread,&QThread::finished,m_pDeal,&QObject::deleteLater);
    connect(m_pDeal,&MyDeal::sSendFinished,this,&MyTableWgt::ReceiverData);
    connect(m_pDeal,&MyDeal::sSendValueChanaged,this,&MyTableWgt::ReceiverChanged);

    m_thread.start();

构造中mydeal就是我单独开出来的线程,用作数据处理。线程我就不细说了,自己可以网上搜索得知。
connect我们知道是信号和槽,能传输数据,但是你自定义的结构体是不可以进行传输的,所以我们要在数据加载完成时候发出一个信号。让tablewidget进行显示数据

鼠标滚轮事件:

void MyTableWgt::wheelEvent(QWheelEvent *event)
{
    int delta= event->delta();

    int row=m_pDeal->GetCurrentRow();
    if(delta>0)
    {
        if(row<5)
        {
            return;
        }
        else
        {
            row=row-5;  //每次滚动滚轮,向上加载5个
        }
    }
    else
    {
        if(row>m_pDeal->GetDataSize()-100)
        {
            row=m_pDeal->GetDataSize()-100;
        }
        else
        {
            row=row+5;
        }

    }

   m_pDeal->LoadData(row);
}

我们获取到当前滚轮是向上或向下滚动,然后从处理数据类中获取当前是第几个,如果鼠标向下滚动就是在原有基础上向下加载5个。反之亦然。

拖动滚动条:

void MyTableWgt::OnVertivalValueChanged(int i_value)
{
    if(i_value==this->verticalScrollBar()->maximum())
    {
        int row=m_pDeal->GetCurrentRow();

        if(row>m_pDeal->GetDataSize()-200)
        {
            row=m_pDeal->GetDataSize()-100;
        }
        else
        {
            row=row+100;
            this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()*0.9);
        }
        m_pDeal->LoadData(row);
    }
    if(i_value==this->verticalScrollBar()->minimum())
    {
        int row=m_pDeal->GetCurrentRow();
        if(row>=100)
        {
            row=row-100;
            if(row<100)
            {
                row=0;
            }
            this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum()*0.1);
        }
        m_pDeal->LoadData(row);
    }
}

原理就是和wheelevent事件原理差不多,但是需要注意的是,不能让滚动为最大值或最小值,不然就不能继续加载数据了。

第一次加载数据:

void MyTableWgt::ReceiverData()
{
    this->ClearAllRow();
    QList<myData> dataList=m_pDeal->GetFirstData();
    this->setRowCount(dataList.size());
    for(int i=0;i<dataList.size();i++)  //首次加载100个
    {
        myData data=dataList[i];
        this->setItem(i,0,new QTableWidgetItem(data.str0));
        this->setItem(i,1,new QTableWidgetItem(data.str1));
        this->setItem(i,2,new QTableWidgetItem(data.str2));
        this->setItem(i,3,new QTableWidgetItem(data.str3));
        this->setItem(i,4,new QTableWidgetItem(data.str4));
        this->setItem(i,5,new QTableWidgetItem(data.str5));
        this->setItem(i,6,new QTableWidgetItem(data.str6));
        this->setItem(i,7,new QTableWidgetItem(data.str7));
        this->setItem(i,8,new QTableWidgetItem(data.str8));
        this->setItem(i,9,new QTableWidgetItem(data.str9));
        this->setItem(i,10,new QTableWidgetItem(data.str10));
    }
}

默认界面就是显示100个,因为加载100万数据是需要时间的,所以当数据又100个的时候,我就会进行加载一次。

当滚动滚轮或滑动滚动条

void MyTableWgt::ReceiverChanged()
{
    this->ClearAllRow();
    this->setRowCount(100);
    //int currentRowcount=this->rowCount();

    QList<myData> dataList=m_pDeal->GetSendData();
    this->setRowCount(100);
    int k=0;
    for(int i=0;i<dataList.size();i++)
    {
        myData data=dataList[i];
        this->setItem(i,0,new QTableWidgetItem(data.str0));
        this->setItem(i,1,new QTableWidgetItem(data.str1));
        this->setItem(i,2,new QTableWidgetItem(data.str2));
        this->setItem(i,3,new QTableWidgetItem(data.str3));
        this->setItem(i,4,new QTableWidgetItem(data.str4));
        this->setItem(i,5,new QTableWidgetItem(data.str5));
        this->setItem(i,6,new QTableWidgetItem(data.str6));
        this->setItem(i,7,new QTableWidgetItem(data.str7));
        this->setItem(i,8,new QTableWidgetItem(data.str8));
        this->setItem(i,9,new QTableWidgetItem(data.str9));
        this->setItem(i,10,new QTableWidgetItem(data.str10));
        k++;
    }
}

记住一句画,界面始终显示100条数据

加载数据类:
初始加载数据:

void MyDeal::CreateData(QString i_path)
{
    m_CurrentRow=0;
    QFile file(i_path);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    int i=0;
    while (!file.atEnd())
    {
        QString strLine=file.readLine();

        QStringList strList=strLine.split("&");

        myData data;
        data.str0=strList[0];
        data.str1=strList[1];
        data.str2=strList[2];
        data.str3=strList[3];
        data.str4=strList[4];
        data.str5=strList[5];
        data.str6=strList[6];
        data.str7=strList[7];
        data.str8=strList[8];
        data.str9=strList[9];
        data.str10=strList[10];
        m_DataList.append(data);

        if(i<=100)
        {
            m_FirstData.append(data);
        }

        if(i==100)
        {
           emit sSendFinished();
        }

        i++;

    }
    m_DataSize=m_DataList.size();
}

mydata是自定义数据类,就是简单的存储数据。

当数据改变时候:

m_SendData.clear();
    for(int i=row;i<row+100;i++)
    {
        myData data=m_DataList[i];
        m_SendData.append(data);
    }
    m_CurrentRow=row;
    emit sSendValueChanaged();

先拿到需要改变的数据,然后将数据发送给界面,界面进行刷新。

看下运行效果:
在这里插入图片描述
这是我需要加载的文件,3万行,不算多。后面可能会有百万行。这套方法绝对承受的住百万条数据!!

在这里插入图片描述
可以看到数据一直在往下加载,但没有消耗任何的内存。

全部代码到这里下载。
ヾ( ̄▽ ̄)ByeBye

  • 39
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加油吧,小杜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值