当前位置:网站首页>QTableWidget懒加载剩内存,不卡!
QTableWidget懒加载剩内存,不卡!
2022-07-03 01:06:00 【kchmmd】
前言
用到表格加载数据,少量数据看不出什么异常,当数据过于庞大,特别是表格中可能还加入了一些界面实时刷新如进度条等,那最终体现出来的效果很差,加载卡,占内存。
所以,下面总结分享的是一种懒加载的策略。
加载策略说明
主要有两个点:
1、对于需要实时更新加载的情况,每次加载数据时,不用调clearContents()、removeRow(int row)等方法去清空再new,而是去重复利用上次已经new出的Item,改变其内容为最新即可
2、只加载界面可见范围内Item,数据的具体数量只需通过滚动条的值体现出来,每次改变滚动条时,再去按照上述1去刷新Item的内容
直接上代码
代码结构
mytablewidget.h
#ifndef MYTABLEWIDGET_H
#define MYTABLEWIDGET_H
#include <QTableWidget>
#include <QResizeEvent>
#include <QWheelEvent>
#include <QScrollBar>
#include <QProgressBar>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QMenu>
#include <QContextMenuEvent>
class TableWidget: public QTableWidget
{
public:
TableWidget(QWidget *parent = nullptr):QTableWidget(parent){
}
~TableWidget(){
}
protected:
void wheelEvent(QWheelEvent *event) override {
}//屏蔽鼠标滑轮事件
};
class MyTableWidget: public QWidget
{
public:
MyTableWidget(QWidget *parent = nullptr);
~MyTableWidget();
virtual void InitTable();
virtual void LoadTableWidget();
void UpdateView();
void SetMenu(QMenu* menu);
void SetItemText(int row, int colunm, QString str);
void SetItemProgress(int row, int colunm, double value, double total);
protected:
void wheelEvent(QWheelEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
private:
TableWidget* m_table;
QScrollBar *m_scrollBar;
int m_itemHeight;
int m_currentRow;
int m_dataCnt;
public:
//data
std::map<QString, double> m_mapData;//name boxOffice
QMenu* m_menu = nullptr;
};
#endif // MYTABLEWIDGET_H
mytablewidget.cpp
#include "mytablewidget.h"
MyTableWidget::MyTableWidget(QWidget *parent):QWidget(parent)
{
m_table = new TableWidget(this);
//点击表头排序
// connect(m_table->horizontalHeader(),&QHeaderView::sectionClicked,this,[=](int colunm){
// m_table->sortItems(colunm,Qt::AscendingOrder);
// });
m_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//关闭滚动条
QHBoxLayout* hbox =new QHBoxLayout(this);
hbox->setMargin(0);
hbox->setSpacing(0);
hbox->addWidget(m_table);
m_itemHeight = 20;
m_dataCnt = 0;
m_scrollBar = new QScrollBar(Qt::Vertical);
connect(m_scrollBar,&QScrollBar::valueChanged,this,[=](int value){
// qDebug()<<"value:"<<value;
LoadTableWidget();
});
hbox->addWidget(m_scrollBar);
InitTable();
LoadTableWidget();
}
MyTableWidget::~MyTableWidget()
{
}
void MyTableWidget::InitTable()
{
QStringList headList;
headList<<"序号"<<"影片名"<<"票房(万元)"<<"票房占比";
m_table->setColumnCount(headList.length());
m_table->setHorizontalHeaderLabels(headList);
m_table->verticalHeader()->setVisible(false);//隐藏行号
m_table->verticalHeader()->setDefaultSectionSize(m_itemHeight);//默认行高
m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//自动分均每列列宽
//m_table->horizontalHeader()->setMinimumSectionSize(100);//默认列宽
m_table->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);//表头居中对齐
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);//以行为单位选择
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);//禁止编辑
m_table->horizontalHeader()->setStyleSheet("QHeaderView::section{background-color:rgb(216,226,236);"
"border:0.5px solid rgb(254,254,254);}");
}
void MyTableWidget::SetItemText(int row, int colunm, QString str)
{
QTableWidgetItem* item = m_table->item(row, colunm);
if(nullptr == item)
{
item = new QTableWidgetItem;
m_table->setItem(row, colunm, item);
}
item->setText(str);
}
void MyTableWidget::SetItemProgress(int row, int colunm, double value, double total)
{
QWidget *widget = m_table->cellWidget(row, colunm);
QProgressBar* bar = static_cast<QProgressBar*>(widget);
if(nullptr == bar)
{
bar = new QProgressBar;
bar->setObjectName("progress");
m_table->setCellWidget(row, colunm, bar);//设置后会自动show
bar->hide();//先hide 加载完会自动show
}
double percent =(double) value/total;
bar->setAlignment(Qt::AlignCenter);
bar->setRange(0,100);
bar->setValue(percent*100);
bar->setFormat(QString("%1%").arg(QString::number(percent*100,'f',1)));
}
void MyTableWidget::LoadTableWidget()
{
int oldRow = m_table->rowCount() - 1;
if(m_currentRow < oldRow)//如果item有了就不删了重新创建,在之前item修改内容即可,界面尺寸改变,显示的行就改变,多了就删除,
for (int i=oldRow - 1; i>oldRow - m_currentRow - 1; i--)
{
m_table->removeRow(i);
}
m_table->setRowCount(m_currentRow+1);
int total = 1000;
std::map<QString, double>::iterator itor = m_mapData.begin();
int beginRow = m_scrollBar->value();//滚动条值,表格行
for (int i=0; i<beginRow; i++){
itor++;}//从滚动条的值对应显示
for (int i =0 ; i<m_currentRow; i++,itor++)
{
if(itor == m_mapData.end())
{
m_table->removeRow(i);
break;
}
SetItemText(i, 0, QString::number(beginRow++));
SetItemText(i, 1, itor->first);
SetItemText(i, 2, QString::number(itor->second,'f',2));
SetItemProgress(i, 3, itor->second, total);
}
}
void MyTableWidget::UpdateView()
{
LoadTableWidget();
}
void MyTableWidget::SetMenu(QMenu *menu)
{
m_menu = menu;
}
void MyTableWidget::resizeEvent(QResizeEvent *event)
{
m_currentRow = height()/m_itemHeight;
m_dataCnt = m_mapData.size();
if(m_dataCnt - m_currentRow > 0)
{
m_scrollBar->setRange(0,m_dataCnt - m_currentRow + 2);
m_scrollBar->show();
}
else
{
m_scrollBar->setRange(0,0);
m_scrollBar->hide();
}
LoadTableWidget();
}
void MyTableWidget::contextMenuEvent(QContextMenuEvent *event)
{
QTableWidgetItem* item = m_table->itemAt(event->pos());
if(item && m_menu)
m_menu->exec(event->globalPos());
}
void MyTableWidget::wheelEvent(QWheelEvent *event)
{
int value = m_scrollBar->value();
if(event->delta() > 0)
{
value -= m_currentRow;
if(value < m_scrollBar->minimum())
value = m_scrollBar->minimum();
m_scrollBar->setValue(value);
}
else
{
value += m_currentRow;
if(value > m_scrollBar->maximum())
value = m_scrollBar->maximum();
m_scrollBar->setValue(value);
}
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "mytablewidget.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
QString GetStr();
private:
Ui::Widget *ui;
MyTableWidget* m_myTable;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QHBoxLayout>
#include <QTimer>
#include <QHeaderView>
#include <QProgressBar>
#include <QScrollBar>
#include <QActionGroup>
#include <QMessageBox>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("TableWidget加载-动态加载-只加载显示区域");//放在 ui->setupUi(this); 之后不然没效果
qsrand(time(nullptr));
m_myTable=new MyTableWidget(this);
QHBoxLayout* hbox =new QHBoxLayout(this);
hbox->setMargin(0);
hbox->setSpacing(0);
hbox->addWidget(m_myTable);
int dataCnt = 134217;
for (int i=0; i<dataCnt;i++) {
double value = rand()%1000000+1000;
m_myTable->m_mapData[GetStr()] = value/100;
}
QMenu* menu = new QMenu(this);
connect(menu,&QMenu::triggered,this,[=](QAction* action){
QString str = action->text();
if("test_1" == action->text())
{
QMessageBox::information(nullptr,"Info","you choice test_1");
}
else if("test2" == action->text())
{
QMessageBox::information(nullptr,"Info","you choice test2");
}
else if("test1" == action->text())
{
QMessageBox::information(nullptr,"Info","you choice test1");
}
});
QMenu* menu_1 = new QMenu("test",this);
m_myTable->SetMenu(menu);
QAction *action_Desc = new QAction("test1");
QAction *action_Asce = new QAction("test2");
action_Desc->setCheckable(true);
action_Asce->setCheckable(true);
action_Asce->setChecked(true);
QActionGroup *group = new QActionGroup(this);
group->addAction(action_Asce);
group->addAction(action_Desc);
menu_1->addAction(action_Desc);
menu_1->addAction(action_Asce);
menu->addMenu(menu_1);
menu->addAction("test_1");
QTimer* m_timer = new QTimer(this);
connect(m_timer,&QTimer::timeout,this,[=]()mutable{
std::map<QString, double>::iterator itor = m_myTable->m_mapData.begin();
for (; itor!=m_myTable->m_mapData.end();itor++) {
double value = rand()%1000000+1000;
itor->second = value/100;
}
m_myTable->UpdateView();
});
m_timer->start(1000);
}
Widget::~Widget()
{
delete ui;
}
QString Widget::GetStr()
{
int length = rand()%15+5;
const char ch[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int size = sizeof(ch);
char* str = new char[length + 1];
int num = 0;
int i;
for (i = 0; i < length; ++i)
{
num = rand() % (size - 1);
str[i] = ch[num];
}
str[i] = '\0';
QString res(str);
//return res;
return "《"+res+"》";
}
总结
有兴趣自己可以对比一下,我分享的和正常一次加载百万级别的数据到表格中,这俩种方式,看下程序内存,和加载速度,逻辑处理还是很快的 ,绘制UI确实比较慢,占内存。理论上,我分享的这种策略加载数据的大小上限,主要就跟数据存储方式和容量有关了,毕竟加载界面可视范围的Item还是比较快的.,但是比如你用容器map存储还是有上限的。
边栏推荐
- MySQL --- 数据库查询 - 基本查询
- MySQL
- Look at how clothing enterprises take advantage of the epidemic
- 数学知识:台阶-Nim游戏—博弈论
- 不登陆或者登录解决oracle数据库账号被锁定。
- [androd] module dependency replacement of gradle's usage skills
- On Fibonacci sequence
- SwiftUI 组件大全之使用 SceneKit 和 SwiftUI 构建交互式 3D 饼图(教程含源码)
- Excel if formula determines whether the two columns are the same
- Excel calculates the difference between time and date and converts it into minutes
猜你喜欢
Excel calculates the difference between time and date and converts it into minutes
What is tone. Diao's story
How wide does the dual inline for bread board need?
Database SQL language 02 connection query
Androd gradle's substitution of its use module dependency
Asynchronous, email and scheduled tasks
Draw love with go+ to express love to her beloved
leetcode:701. Insertion in binary search tree [BST insertion]
[C language] detailed explanation of pointer and array written test questions
[fh-gfsk] fh-gfsk signal analysis and blind demodulation research
随机推荐
Mathematical knowledge: divisible number inclusion exclusion principle
leetcode:871. Minimum refueling times [Pat has done before + maximum stacking + greed]
[FPGA tutorial case 5] ROM design and Implementation Based on vivado core
Excel calculates the difference between time and date and converts it into minutes
C application interface development foundation - form control (3) - file control
【QT】自定义控件的封装
d,ldc构建共享库
d,ldc構建共享庫
Excel if formula determines whether the two columns are the same
每日一题之干草堆的移动
C#应用程序界面开发基础——窗体控制(3)——文件类控件
Machine learning terminology
The latest analysis of tool fitter (technician) in 2022 and the test questions and analysis of tool fitter (technician)
Concise analysis of redis source code 11 - Main IO threads and redis 6.0 multi IO threads
Arduino DY-SV17F自动语音播报
MySQL foundation 04 MySQL architecture
Matlab Doppler effect produces vibration signal and processing
[shutter] animation animation (the core class of shutter animation | animation | curvedanimation | animationcontroller | tween)
Esp32 simple speed message test of ros2 (limit frequency)
Is there anything in common between spot gold and spot silver