当前位置:网站首页>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存储还是有上限的。
边栏推荐
- Androd gradle's substitution of its use module dependency
- How wide does the dual inline for bread board need?
- C application interface development foundation - form control (4) - selection control
- MySQL basic usage 02
- Give you an array numbers that may have duplicate element values. It was originally an array arranged in ascending order, and it was rotated once according to the above situation. Please return the sm
- MySQL - database query - condition query
- 【FH-GFSK】FH-GFSK信号分析与盲解调研究
- 每日一题之干草堆的移动
- Mathematical knowledge: Nim game game theory
- Concise analysis of redis source code 11 - Main IO threads and redis 6.0 multi IO threads
猜你喜欢

Expérience de recherche d'emploi d'un programmeur difficile

Excel calculates the difference between time and date and converts it into minutes

Wireshark data analysis and forensics a.pacapng

Arduino dy-sv17f automatic voice broadcast

什么是调。调的故事

给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。【剑指Offer】

Strongly connected components of digraph
![[principles of multithreading and high concurrency: 2. Solutions to cache consistency]](/img/ce/5c41550ed649ee7cada17b0160f739.jpg)
[principles of multithreading and high concurrency: 2. Solutions to cache consistency]

Database SQL language 02 connection query
![leetcode:701. Insertion in binary search tree [BST insertion]](/img/bc/1dda73198488eb81b49be2c1dff6c2.png)
leetcode:701. Insertion in binary search tree [BST insertion]
随机推荐
什么是调。调的故事
Matlab Doppler effect produces vibration signal and processing
Basis of information entropy
Meibeer company is called "Manhattan Project", and its product name is related to the atomic bomb, which has caused dissatisfaction among Japanese netizens
【C语言】指针与数组笔试题详解
Mathematical knowledge: divisible number inclusion exclusion principle
The meaning of wildcard, patsubst and notdir in makefile
Dotconnect for PostgreSQL data provider
MySQL basic usage 02
【FPGA教程案例6】基于vivado核的双口RAM设计与实现
Kivy教程大全之 创建您的第一个kivy程序 hello word(教程含源码)
每日一题之干草堆的移动
[system analyst's road] Chapter V double disk software engineering (development model development method)
Canvas drawing -- bingdd
JDBC courses
Key wizard hit strange learning - automatic path finding back to hit strange points
Mathematical knowledge: Nim game game theory
leetcode:701. Insertion in binary search tree [BST insertion]
MySQL --- 数据库查询 - 基本查询
MySQL