Memory leak using StyleSheet
-
Hello, I have problem with memory, when I use setStyle("Fusion") and custom style for specific elements (like rows in my table) I have huge memory usage from nothing. I create this project to show problem (in main project I use custom qss file to set styles for table and result is the same). Memory increase by scrolling and just moving mouse.
It would be really cool, if someone could helpmain.cpp
#include "table.h" #include <QApplication> #include <QGridLayout> #include <QLabel> #include <QMainWindow> #include <QWidget> int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setStyle("Fusion"); QWidget *widget = new QWidget; widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QGridLayout *_gLayout = new QGridLayout; _gLayout->setContentsMargins(QMargins()); EditDigitalSignalWidget *table = new EditDigitalSignalWidget(10'000); _gLayout->addWidget(table, 0, 0); widget->setLayout(_gLayout); widget->resize(700, 500); widget->show(); return a.exec(); }
table.h
#ifndef TABLE_H #define TABLE_H #include <QAbstractTableModel> #include <QComboBox> #include <QGridLayout> #include <QGuiApplication> #include <QHeaderView> #include <QLabel> #include <QPushButton> #include <QResizeEvent> #include <QScreen> #include <QScrollBar> #include <QSpacerItem> #include <QSpinBox> #include <QStyledItemDelegate> #include <QTableView> #include <QVBoxLayout> #include <QWidget> namespace { // CellWidget [[maybe_unused]] constexpr int cellWidgetWidth = 100; [[maybe_unused]] constexpr int cellWidgetHeight = 20; [[maybe_unused]] constexpr int spinBoxDurationMinDynamic = 1; [[maybe_unused]] constexpr int spinBoxDurationMaxDynamic = std::numeric_limits<int>::max(); // Table Header [[maybe_unused]] constexpr int tableHeaderHeight = cellWidgetHeight; [[maybe_unused]] constexpr int tableHeaderNumberWidth = 45; [[maybe_unused]] constexpr int tableHeaderTimeWidth = 65; [[maybe_unused]] constexpr int tableHeaderDurationWidth = 73; [[maybe_unused]] constexpr int tableHeaderStateWidth = 65; // Table (EditDigitalSignalWidget) [[maybe_unused]] constexpr int tableRowHeight = cellWidgetHeight; [[maybe_unused]] constexpr int tableLayoutHeightReserve = tableRowHeight; [[maybe_unused]] constexpr int tableMinimalHeight = 3 * tableRowHeight + tableLayoutHeightReserve; [[maybe_unused]] int tableMinWidthConst = tableHeaderNumberWidth + tableHeaderTimeWidth + tableHeaderDurationWidth + tableHeaderStateWidth + 40; // PwmWidget [[maybe_unused]] constexpr int pwmPulseMin = 1; [[maybe_unused]] constexpr int pwmPulseMax = std::numeric_limits<int>::max(); } // namespace class HeaderWidget : public QWidget { public: HeaderWidget(QWidget *parent = nullptr); private: void initNumber(); void initTime(); void initDuration(); void initState(); QScopedPointer<QLabel> _number; QScopedPointer<QLabel> _time; QScopedPointer<QLabel> _duration; QScopedPointer<QLabel> _state; QHBoxLayout *_hLayout = nullptr; }; class CellWidget : public QWidget { public: CellWidget(size_t index, QWidget *parent = nullptr); void setData(size_t index); void selectWidget(); private: void initNumber(); void initTime(); void initDuration(); void initState(); void updateDuration(); QScopedPointer<QLabel> _number; QScopedPointer<QLabel> _time; QScopedPointer<QSpinBox> _duration; QScopedPointer<QPushButton> _state; QHBoxLayout *_hLayout; size_t _index = 0; }; /* ---------------------------------------------------------------------- EditDigitalSignalWidget */ class EditDigitalSignalWidget : public QWidget { public: EditDigitalSignalWidget(size_t size, QWidget *parent = nullptr); virtual void resizeEvent(QResizeEvent *event) override; virtual void wheelEvent(QWheelEvent *event) override; private: void initScrollBar(); void initHeader(); void initWidgetRows(int height); void onScrollTableUpdate(int min, int max); void onTableResize(int newMin, int newMax); void updateScrollBar(int height); QScopedPointer<QScrollBar> _scrollBar; QScopedPointer<HeaderWidget> _header; std::vector<std::unique_ptr<CellWidget>> _widgets; QVBoxLayout *_innerVLayout = nullptr; QGridLayout *_mainGLayout = nullptr; bool isInitialized = false; size_t _size = 0; }; /* ---------------------------------------------------------------------------------------------- */ #endif // TABLE_H
table.cpp
#include "table.h" HeaderWidget::HeaderWidget(QWidget *parent) : QWidget(parent) { _hLayout = new QHBoxLayout(); _hLayout->setAlignment(Qt::AlignHCenter | Qt::AlignTop); _hLayout->setContentsMargins({}); _hLayout->setSpacing(0); initNumber(); initTime(); initDuration(); initState(); setFixedHeight(tableHeaderHeight); setLayout(_hLayout); } void HeaderWidget::initNumber() { _number.reset(new QLabel(this)); _number->setObjectName("EditTableHeaderNumber"); _number->setFixedSize(tableHeaderNumberWidth, tableHeaderHeight); _hLayout->addWidget(_number.get()); } void HeaderWidget::initTime() { _time.reset(new QLabel(this)); _time->setStyleSheet( "background:rgb(60,60,60);" "border-top:1px solid palette(dark);" "border-bottom:1px solid palette(dark);" "padding-right:5px;" "padding-left:5px;"); _time->setAlignment(Qt::AlignCenter); _time->setText("Time"); _time->setFixedHeight(tableHeaderHeight); _time->setMinimumWidth(tableHeaderTimeWidth); _time->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed); _hLayout->addWidget(_time.get()); } void HeaderWidget::initDuration() { _duration.reset(new QLabel(this)); _duration->setStyleSheet( "background:rgb(60,60,60);" "border-top:1px solid palette(dark);" "border-bottom:1px solid palette(dark);" "padding-right:5px;" "padding-left:5px;"); _duration->setAlignment(Qt::AlignCenter); _duration->setText("Duration"); _duration->setFixedHeight(tableHeaderHeight); _duration->setMinimumWidth(tableHeaderDurationWidth); _duration->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed); _hLayout->addWidget(_duration.get()); } void HeaderWidget::initState() { _state.reset(new QLabel(this)); _state->setStyleSheet( "background:rgb(60,60,60);" "border-top:1px solid palette(dark);" "border-right:1px solid palette(dark);" "border-bottom:1px solid palette(dark);" "padding-right:5px;" "padding-left:5px;"); _state->setAlignment(Qt::AlignCenter); _state->setText("State"); _state->setFixedSize(tableHeaderStateWidth, tableHeaderHeight); _hLayout->addWidget(_state.get()); } CellWidget::CellWidget(size_t index, QWidget *parent) : QWidget(parent), _index(index) { _hLayout = new QHBoxLayout(); _hLayout->setAlignment(Qt::AlignHCenter | Qt::AlignTop); _hLayout->setContentsMargins(QMargins()); _hLayout->setSpacing(0); initNumber(); initTime(); initDuration(); initState(); setFixedHeight(tableHeaderHeight); setLayout(_hLayout); } void CellWidget::setData(size_t index) { _index = index; const QString n = QString::number(index + 1); const QString time = QString::number(index + 1); const QString state = QString::number(index + 1); _number->blockSignals(true); _time->blockSignals(true); _duration->blockSignals(true); _state->blockSignals(true); _number->setText(n); _time->setText(time); updateDuration(); _state->setText(state); _number->blockSignals(false); _time->blockSignals(false); _duration->blockSignals(false); _state->blockSignals(false); if (_duration->hasFocus()) _duration->clearFocus(); } void CellWidget::selectWidget() { _duration->setFocus(); } void CellWidget::initNumber() { _number.reset(new QLabel(this)); _number->setStyleSheet( "background:rgb(60,60,60);" "border:1px solid palette(dark);" "border-top-style: none;" "padding-left:5px;" "padding-right:5px;"); _number->setAlignment(Qt::AlignCenter); _number->setFixedSize(tableHeaderNumberWidth, tableHeaderHeight); _hLayout->addWidget(_number.get()); } void CellWidget::initTime() { _time.reset(new QLabel(this)); _time->setStyleSheet( "background-color:rgb(205, 205, 205);" "border:1px solid palette(dark);" "border-top-style: none;" "border-left-style: none;"); _time->setAlignment(Qt::AlignLeft); _time->setFixedHeight(tableHeaderHeight); _time->setMinimumWidth(tableHeaderTimeWidth); _time->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed); _hLayout->addWidget(_time.get(), 1); _hLayout->addSpacing(1); } void CellWidget::initDuration() { _duration.reset(new QSpinBox(this)); _duration->setStyleSheet(" background-color:rgb(205, 205, 205);"); _duration->setFixedHeight(tableHeaderHeight); _duration->setMinimumWidth(tableHeaderDurationWidth); _duration->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed); _hLayout->addWidget(_duration.get(), 1); // connect(_duration.get(), &QSpinBox::valueChanged, this, &CellWidget::onDurationChanged); } void CellWidget::initState() { _state.reset(new QPushButton(this)); _state->setStyleSheet(" background-color:rgb(205, 205, 205);"); _state->setFixedSize(tableHeaderStateWidth, tableHeaderHeight); _state->setMinimumWidth(tableHeaderStateWidth); _state->setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed); _hLayout->addWidget(_state.get()); } void CellWidget::updateDuration() { _duration->setMinimum(spinBoxDurationMinDynamic); _duration->setMaximum(spinBoxDurationMaxDynamic); const QString durationSuffix = "M"; _duration->setValue(_index); _duration->setSuffix(durationSuffix); } EditDigitalSignalWidget::EditDigitalSignalWidget(size_t size, QWidget *parent) : QWidget(parent), _size(size) { // Init layout setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding); setMinimumHeight(tableMinimalHeight); _mainGLayout = new QGridLayout; _mainGLayout->setAlignment(Qt::AlignTop); _mainGLayout->setSpacing(1); _innerVLayout = new QVBoxLayout(); _innerVLayout->setSpacing(0); _innerVLayout->setAlignment(Qt::AlignTop | Qt::AlignHCenter); _mainGLayout->addLayout(_innerVLayout, 0, 0); initScrollBar(); initHeader(); setLayout(_mainGLayout); } void EditDigitalSignalWidget::onScrollTableUpdate(int min, int max) { // Round bottom border max -= max % tableRowHeight; // Add widgets to layout for (int i = 0, pos = min; pos < max - tableLayoutHeightReserve && i < _widgets.size(); ++i, pos += tableRowHeight) { const int index = pos / tableRowHeight; if (index >= _size) break; _widgets[i]->setData(index); } } void EditDigitalSignalWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); if (event->size().height() == event->oldSize().height()) return; const int widgetHeight = event->size().height() - tableHeaderHeight; updateScrollBar(widgetHeight); if (!isInitialized) initWidgetRows(widgetHeight); else onTableResize(_scrollBar->value(), _scrollBar->value() + widgetHeight); } void EditDigitalSignalWidget::wheelEvent(QWheelEvent *event) { _scrollBar->event(event); } void EditDigitalSignalWidget::initScrollBar() { _scrollBar.reset(new QScrollBar(this)); _scrollBar->setSingleStep(tableRowHeight); _scrollBar->setPageStep(tableRowHeight); _mainGLayout->addWidget(_scrollBar.get(), 0, 1); connect(_scrollBar.get(), &QScrollBar::valueChanged, this, [&](auto pos) { return onScrollTableUpdate(pos, pos + this->height()); }); updateScrollBar(this->height()); } void EditDigitalSignalWidget::initHeader() { _header.reset(new HeaderWidget(this)); _innerVLayout->addWidget(_header.get()); } void EditDigitalSignalWidget::initWidgetRows(int height) { // Calculate max buttons number depending on screen const auto screens = QGuiApplication::screens(); int _maxWidgetNumber = 0; for (int i = 0; i < screens.size(); ++i) { const int temp = screens[i]->geometry().height() / tableRowHeight; if (temp > _maxWidgetNumber) _maxWidgetNumber = temp; } blockSignals(true); // Round bottom border height -= height % tableRowHeight; // Add new widgets for (int i = 0, pos = 0; i < _maxWidgetNumber; ++i, pos += tableRowHeight) { const int index = pos / tableRowHeight; std::unique_ptr<CellWidget> rowWidget(new CellWidget(index, this)); _widgets.push_back(std::move(rowWidget)); _widgets.back()->setMinimumHeight(1); _innerVLayout->addWidget(_widgets.back().get()); if (pos < height - tableLayoutHeightReserve && i < _size) _widgets[i]->setData(index); else _widgets[i]->hide(); } blockSignals(false); isInitialized = true; } void EditDigitalSignalWidget::onTableResize(int newMin, int newMax) { blockSignals(true); // Remove widgets from layout for (int i = 0; i < _widgets.size(); ++i) { _widgets[i]->hide(); } // Round bottom border newMax -= newMax % tableRowHeight; // Add widgets to layout for (int i = 0, pos = newMin; i < _widgets.size() && pos < newMax - tableLayoutHeightReserve; ++i, pos += tableRowHeight) { const int index = pos / tableRowHeight; if (index >= _size) break; _widgets[i]->setData(index); _widgets[i]->show(); } blockSignals(false); } void EditDigitalSignalWidget::updateScrollBar(int height) { int scrollBarMax = static_cast<int>(_size) * tableRowHeight - height + tableLayoutHeightReserve; // Hide when there are too little widgets if (scrollBarMax <= 0) { _scrollBar->setMinimum(0); _scrollBar->setMaximum(0); _scrollBar->hide(); return; } // Round up if (scrollBarMax % tableRowHeight != 0) scrollBarMax += tableRowHeight - scrollBarMax % tableRowHeight; _scrollBar->setMaximum(scrollBarMax); _scrollBar->show(); }
memory from start:
memory after moving:
-
Thanks for the comprehensive example!
I have briefly run it by vagrind. There's high memory consumption but no leak at first glance.
The code is instantiating 30.000 widgets, each of them with a style sheet. The style sheets define colors, partly border brushes and padding. Each time you scroll, new widgets get paint events and their style sheets are parsed from a string. These operations are relatively expensive and 30k is not a small a multiplier.
To save memory and gain speed, you could try assigning the style information in a QPalette instead of a style sheet. You might struggle with the padding - borders and colors should work. -
Thank you a lot, this problem is important for me. I will try your way.
- But I wrote the table so widget number doesn't depend on number of rows (max number is about 54) and I just change text on existing widgets. That's why I don't understand when memory is incremented and not freed
- One question about your answer. How to do it?) As I understood, re-implement paintEvent, then with QPainter, draw rectangle like border. Or you said about more simple method.
-
One more thing, I tried to add styles to qss file (for table they are style-properties starts with #, after comments)., but result is the same.
darkstyle.h
#ifndef DARKSTYLE_H #define DARKSTYLE_H #include <QApplication> #include <QFile> #include <QFont> #include <QPainter> #include <QProxyStyle> #include <QStyleFactory> #include <QWidget> class DarkStyle : public QProxyStyle { Q_OBJECT public: DarkStyle(); explicit DarkStyle(QStyle *style); QStyle *baseStyle() const; void polish(QPalette &palette) override; void polish(QApplication *app) override; private: QStyle *styleBase(QStyle *style = nullptr) const; }; #endif // DARKSTYLE_H
darkstyle.cpp
#include "darkstyle.h" DarkStyle::DarkStyle() : DarkStyle(styleBase()) {} DarkStyle::DarkStyle(QStyle *style) : QProxyStyle(style) {} QStyle *DarkStyle::styleBase(QStyle *style) const { static QStyle *base = !style ? QStyleFactory::create(QStringLiteral("Fusion")) : style; return base; } QStyle *DarkStyle::baseStyle() const { return styleBase(); } void DarkStyle::polish(QPalette &palette) { // modify palette to dark palette.setColor(QPalette::Window, QColor(53, 53, 53)); palette.setColor(QPalette::WindowText, Qt::white); palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127)); palette.setColor(QPalette::Base, QColor(42, 42, 42)); palette.setColor(QPalette::AlternateBase, QColor(66, 66, 66)); palette.setColor(QPalette::ToolTipBase, Qt::white); palette.setColor(QPalette::ToolTipText, QColor(53, 53, 53)); palette.setColor(QPalette::Text, Qt::white); palette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127)); palette.setColor(QPalette::Dark, QColor(35, 35, 35)); palette.setColor(QPalette::Shadow, QColor(20, 20, 20)); palette.setColor(QPalette::Button, QColor(53, 53, 53)); palette.setColor(QPalette::ButtonText, Qt::white); palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127)); palette.setColor(QPalette::BrightText, Qt::red); palette.setColor(QPalette::Link, QColor(42, 130, 218)); palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80)); palette.setColor(QPalette::HighlightedText, Qt::white); palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127)); } void DarkStyle::polish(QApplication *app) { if (!app) return; // increase font size for better reading, // setPointSize was reduced from +2 because when applied this way in Qt5, the // font is larger than intended for some reason QFont defaultFont = QApplication::font(); defaultFont.setPointSize(defaultFont.pointSize()); app->setFont(defaultFont); // loadstylesheet QFile qfDarkstyle(QStringLiteral(":/darkstyle/darkstyle.qss")); if (qfDarkstyle.open(QIODevice::ReadOnly | QIODevice::Text)) { // set stylesheet QString qsStylesheet = QString::fromLatin1(qfDarkstyle.readAll()); app->setStyleSheet(qsStylesheet); qfDarkstyle.close(); } }
darkstyle.qss
QScrollBar::handle:horizontal:hover{ background-color:palette(highlight); } QScrollBar::add-line:horizontal{ background:none; width:0px; subcontrol-position:bottom; subcontrol-origin:margin; } QScrollBar::sub-line:horizontal{ background:none; width:0px; subcontrol-position:top; subcontrol-origin:margin; } QSlider::handle:horizontal{ border-radius:4px; border:1px solid rgba(25,25,25,255); background-color:palette(alternate-base); min-height:20px; margin:0 -4px; } QSlider::handle:horizontal:hover{ background:palette(highlight); } QSlider::add-page:horizontal{ background:palette(base); } QSlider::sub-page:horizontal{ background:palette(highlight); } QSlider::sub-page:horizontal:disabled{ background:rgb(80,80,80); } /* EditDigitalSignalTable */ /* Table cells */ QLabel#EditTableCells{ background-color:palette(base); border:1px solid palette(dark); border-top-style: none; border-left-style: none; padding-left:5px; padding-right:5px; } QPushButton#EditTableCells, QSpinBox#EditTableCells{ background-color:palette(base); } /* Table headers */ #EditTableHeaderTime, #EditTableHeaderDuration{ background:rgb(60,60,60); border-top:1px solid palette(dark); border-bottom:1px solid palette(dark); padding-left:5px; padding-right:5px; } #EditTableHeaderState{ background:rgb(60,60,60); border-top:1px solid palette(dark); border-right:1px solid palette(dark); border-bottom:1px solid palette(dark); padding-left:5px; padding-right:5px; } /* Table corner cell */ #EditTableHeaderNumber{ border:1px solid palette(dark); padding-left:5px; padding-right:5px; background:rgb(90,90,90); } QTableView QTableCornerButton::section{ background:rgb(75,75,75); } /* Table vertical header */ #EditTableCellNumber{ background:rgb(60,60,60); border:1px solid palette(dark); border-top-style: none; padding-left:5px; padding-right:5px; } /* Tab-widget that contains edit-table*/ #EditTabWidget{ background:rgb(53,53,53); }
-
You don't have to re-implement the paint event.
Just instead of using stylesheets I would use a standard style shipped with Qt.
Depending on your operating system and window manager, a suitable default style will be chosen automatically.
Instead of callingsetStyleSheet()
on your widget, you read its palette, set the respective brush and callwidget->setPalette()
again. A paint event will then be posted and your widget gets painted without a style sheet string having to be interpreted.
Please read the documentation of QPalette, which I have linked in my previous post. Everything is explained there and you can also examine code examples. -
You don't have to re-implement the paint event.
Just instead of using stylesheets I would use a standard style shipped with Qt.
Depending on your operating system and window manager, a suitable default style will be chosen automatically.
Instead of callingsetStyleSheet()
on your widget, you read its palette, set the respective brush and callwidget->setPalette()
again. A paint event will then be posted and your widget gets painted without a style sheet string having to be interpreted.
Please read the documentation of QPalette, which I have linked in my previous post. Everything is explained there and you can also examine code examples.@Axel-Spoerl, yes, but how can I create border to widget with QPalette? As I understood reading doc, it works mostly with color, using roles. And one more thing, how to control paint-border for specific sides(not all 4), when I have table?
-
The code manually implements parts of QTableView, respectively QTableWidget. These classes have an out-of-the-box implementation for column headers and row numbers, which your code creates labels for. They also provide a visual grid, which can probably substitute drawing borders around every widget. Such grids can be styled and they are rendered more efficiently: Instead of drawing a rectangle around each widget, they consist of vertical and horizontal lines across the entire viewport. They get repainted only if necessary (e.g. due to resizing or scroll moves below grid size). And as a bycatch, your users will be able to navigate cells with cursor keys - if you allow it to happen.
In case you use QTableView, you can store your data in a QAbstractTableModel, define selection models, which gives you focus on data while leaving its visual representation (including drag & drop, sorting) to the system.
QTableWidget has a simpler API at the cost of less flexibility in data management.
-
The code manually implements parts of QTableView, respectively QTableWidget. These classes have an out-of-the-box implementation for column headers and row numbers, which your code creates labels for. They also provide a visual grid, which can probably substitute drawing borders around every widget. Such grids can be styled and they are rendered more efficiently: Instead of drawing a rectangle around each widget, they consist of vertical and horizontal lines across the entire viewport. They get repainted only if necessary (e.g. due to resizing or scroll moves below grid size). And as a bycatch, your users will be able to navigate cells with cursor keys - if you allow it to happen.
In case you use QTableView, you can store your data in a QAbstractTableModel, define selection models, which gives you focus on data while leaving its visual representation (including drag & drop, sorting) to the system.
QTableWidget has a simpler API at the cost of less flexibility in data management.
@Axel-Spoerl , Yes it does. But I have been working at this task for already 2 weeks and used: QTableWIdget(too much widgets and it doesnt work), QTableView + delegate (but delegates creates only after clicking on cells and it doesnt work immidiately, like QSpinBox and other widgets).
That's why I did this table by my own . And main question: Is re-paint, using paintEvent, best variant or can I use other paint things? -
Feel free to hate me - I am going to be blunt and honest: If heading to the wrong direction, change your way. Pushing, speeding and suspecting others won't get you anywhere. StyleSheets don't leak memory and QTableWidget rocks 30k items with no issue.
I'd call 2 weeks of research an investment in finding out that the hard way is eating memory and CPU as a snack between breakfast and lunch.
Read the documentation carefully and use the tools available for managing large matrices of widgets. If you struggle, this forum will help you.If you stick to your individual implementation, that's totally fine. A price is to be paid for parsing style sheet strings and/or drawing rectangles around each widget. It doesn't matter much, if it's done by generic paint events, or by an individual method that overrides
QWidget::paintEvent
. I trust you understand that we can't be of much help in how to implement QTableWidget without QTableWidget. -
Feel free to hate me - I am going to be blunt and honest: If heading to the wrong direction, change your way. Pushing, speeding and suspecting others won't get you anywhere. StyleSheets don't leak memory and QTableWidget rocks 30k items with no issue.
I'd call 2 weeks of research an investment in finding out that the hard way is eating memory and CPU as a snack between breakfast and lunch.
Read the documentation carefully and use the tools available for managing large matrices of widgets. If you struggle, this forum will help you.If you stick to your individual implementation, that's totally fine. A price is to be paid for parsing style sheet strings and/or drawing rectangles around each widget. It doesn't matter much, if it's done by generic paint events, or by an individual method that overrides
QWidget::paintEvent
. I trust you understand that we can't be of much help in how to implement QTableWidget without QTableWidget.@Axel-Spoerl No, thank you a lot for the help. I am new in Qt and learn all these stuff step by step. Okay, custom implementation will be the best, for my case, because QTableWidget is okay for less than 20'000 (if we have 3 buttons in row), after it it doesn't work. My project uses more than 100'000 points, so it is 3 * 100'000 widgets in general. But thank for your time.
And main rule: NOT use customStyle for table with a lot of rows
I've already written about it:
https://forum.qt.io/topic/137658/table-with-large-amount-of-widgets-100-000 -
Feel free to hate me - I am going to be blunt and honest: If heading to the wrong direction, change your way. Pushing, speeding and suspecting others won't get you anywhere. StyleSheets don't leak memory and QTableWidget rocks 30k items with no issue.
I'd call 2 weeks of research an investment in finding out that the hard way is eating memory and CPU as a snack between breakfast and lunch.
Read the documentation carefully and use the tools available for managing large matrices of widgets. If you struggle, this forum will help you.If you stick to your individual implementation, that's totally fine. A price is to be paid for parsing style sheet strings and/or drawing rectangles around each widget. It doesn't matter much, if it's done by generic paint events, or by an individual method that overrides
QWidget::paintEvent
. I trust you understand that we can't be of much help in how to implement QTableWidget without QTableWidget.@Axel-Spoerl Just curious: you really create 30k items while they can not be displayed at the same time? Is there a way to display only some of them on demand while the data is stored in the model or somewhere? I will never want to create so many items in a table at the same time.
-
@Axel-Spoerl Just curious: you really create 30k items while they can not be displayed at the same time? Is there a way to display only some of them on demand while the data is stored in the model or somewhere? I will never want to create so many items in a table at the same time.
@JoeCFD It would be possible, however, not the most elegant way. QTableView offers rich possibilities to store data in a model and render only what is needed. That's what I would use for large data volumes.
-
@JoeCFD It would be possible, however, not the most elegant way. QTableView offers rich possibilities to store data in a model and render only what is needed. That's what I would use for large data volumes.
@Axel-Spoerl Got it. Thanks. I may have a peek into the source code and see how it is done.