当前位置:网站首页>Qtablewidget lazy load remaining memory, no card!
Qtablewidget lazy load remaining memory, no card!
2022-07-03 01:31:00 【kchmmd】
Preface
Use tables to load data , A small amount of data shows no abnormality , When the data is too large , In particular, some interfaces may be added to the table to refresh in real time, such as the progress bar , The final effect is very poor , Load card , Occupy memory .
therefore , The following summary and sharing is a lazy loading strategy .
Loading policy description
There are two main points :
1、 For situations that require real-time update loading , Every time you load data , Don't tune clearContents()、removeRow(int row) Wait for a way to empty new, But to reuse what was already done last time new Out of Item, Change its content to the latest
2、 Only load within the visible range of the interface Item, The specific amount of data only needs to be reflected by the value of the scroll bar , Every time you change the scroll bar , Then follow the above 1 To refresh Item The content of


Go straight to the code
The code structure 
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 {
}// Shield the mouse pulley event
};
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);
// Click the header to sort
// connect(m_table->horizontalHeader(),&QHeaderView::sectionClicked,this,[=](int colunm){
// m_table->sortItems(colunm,Qt::AscendingOrder);
// });
m_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);// Turn off scroll bar
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<<" Serial number "<<" The title of the film "<<" box office ( Ten thousand yuan )"<<" Box office share ";
m_table->setColumnCount(headList.length());
m_table->setHorizontalHeaderLabels(headList);
m_table->verticalHeader()->setVisible(false);// Hide line numbers
m_table->verticalHeader()->setDefaultSectionSize(m_itemHeight);// Default line height
m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);// Automatically divide the width of each column
//m_table->horizontalHeader()->setMinimumSectionSize(100);// Default column width
m_table->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);// Center the header
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);// Select by behavior unit
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);// No editing
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);// After setting, it will automatically show
bar->hide();// First hide After loading, it will automatically 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)// If item If you have it, don't delete it and create it again , Before item Just change the content , Interface size changes , The displayed line changes , Delete more ,
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();// Scroll bar value , Table row
for (int i=0; i<beginRow; i++){
itor++;}// The corresponding display from the value of the scroll bar
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 load - Dynamic loading - Load only the display area ");// Put it in ui->setupUi(this); After that, it won't work
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+"》";
}
summary
If you are interested, you can compare , I share and normally load millions of levels of data into the table at a time , These two ways , Look at the program memory , And loading speed , Logic processing is still very fast , draw UI It's really slow , Occupy memory . Theoretically , The maximum size of data loaded by this strategy I share , It is mainly related to the data storage method and capacity , After all, the visual range of the loading interface Item It's still faster ., But for example, you use containers map There is still an upper limit to storage .
边栏推荐
- MySQL --- 数据库查询 - 基本查询
- [my advanced journey of OpenGL learning] collation of Euler angle, rotation order, rotation matrix, quaternion and other knowledge
- 音程的知识的总结
- 【系统分析师之路】第五章 复盘软件工程(开发模型开发方法)
- What operations need attention in the spot gold investment market?
- [flutter] icons component (fluttericon Download Icon | customize SVG icon to generate TTF font file | use the downloaded TTF icon file)
- Druid database connection pool
- 按键精灵打怪学习-前台和内网发送后台验证码
- High-Resolution Network (篇一):原理刨析
- What is tone. Diao's story
猜你喜欢

Force buckle 204 Count prime

C#应用程序界面开发基础——窗体控制(3)——文件类控件

并发编程的三大核心问题 -《深入理解高并发编程》

Work experience of a hard pressed programmer

Cut point of undirected graph

MySQL basic usage 02

Why can't the start method be called repeatedly? But the run method can?
![[FPGA tutorial case 6] design and implementation of dual port RAM based on vivado core](/img/fb/c371ffaa9614c6f2fd581ba89eb2ab.png)
[FPGA tutorial case 6] design and implementation of dual port RAM based on vivado core
![[Androd] Gradle 使用技巧之模块依赖替换](/img/5f/968db696932f155a8c4a45f67135ac.png)
[Androd] Gradle 使用技巧之模块依赖替换

Leetcode 6103 - minimum fraction to delete an edge from the tree
随机推荐
ThinkPHP+Redis实现简单抽奖
按键精灵打怪学习-多线程后台坐标识别
Concise analysis of redis source code 11 - Main IO threads and redis 6.0 multi IO threads
[Androd] Gradle 使用技巧之模块依赖替换
How is the mask effect achieved in the LPL ban/pick selection stage?
[system analyst's road] Chapter V double disk software engineering (development model development method)
英语常用词汇
Top ten regular spot trading platforms 2022
Look at how clothing enterprises take advantage of the epidemic
Kivy tutorial how to create drop-down lists in Kivy
MySQL foundation 05 DML language
Androd Gradle 对其使用模块依赖的替换
MySQL - database query - condition query
tail -f 、tail -F、tailf的区别
MySQL基础用法02
并发编程的三大核心问题 -《深入理解高并发编程》
C application interface development foundation - form control (4) - selection control
uniapp组件-uni-notice-bar通告栏
[Arduino experiment 17 L298N motor drive module]
【FH-GFSK】FH-GFSK信号分析与盲解调研究