Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Memory leak using StyleSheet
QtWS25 Last Chance

Memory leak using StyleSheet

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 3 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Z Offline
    Z Offline
    zonman
    wrote on last edited by
    #1

    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 help

    main.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_from_start.jpg
    memory after moving:
    memory_after_moving.jpg

    1 Reply Last reply
    0
    • Axel SpoerlA Offline
      Axel SpoerlA Offline
      Axel Spoerl
      Moderators
      wrote on last edited by
      #2

      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.

      Software Engineer
      The Qt Company, Oslo

      1 Reply Last reply
      2
      • Z Offline
        Z Offline
        zonman
        wrote on last edited by zonman
        #3

        Thank you a lot, this problem is important for me. I will try your way.

        1. 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
        2. 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.
        1 Reply Last reply
        0
        • Z Offline
          Z Offline
          zonman
          wrote on last edited by zonman
          #4

          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);
          }
          
          1 Reply Last reply
          0
          • Axel SpoerlA Offline
            Axel SpoerlA Offline
            Axel Spoerl
            Moderators
            wrote on last edited by
            #5

            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 calling setStyleSheet() on your widget, you read its palette, set the respective brush and call widget->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.

            Software Engineer
            The Qt Company, Oslo

            Z 1 Reply Last reply
            0
            • Axel SpoerlA Axel Spoerl

              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 calling setStyleSheet() on your widget, you read its palette, set the respective brush and call widget->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.

              Z Offline
              Z Offline
              zonman
              wrote on last edited by
              #6

              @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?

              1 Reply Last reply
              0
              • Axel SpoerlA Offline
                Axel SpoerlA Offline
                Axel Spoerl
                Moderators
                wrote on last edited by
                #7

                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.

                Software Engineer
                The Qt Company, Oslo

                Z 1 Reply Last reply
                1
                • Axel SpoerlA Axel Spoerl

                  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.

                  Z Offline
                  Z Offline
                  zonman
                  wrote on last edited by
                  #8

                  @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?

                  1 Reply Last reply
                  0
                  • Axel SpoerlA Offline
                    Axel SpoerlA Offline
                    Axel Spoerl
                    Moderators
                    wrote on last edited by Axel Spoerl
                    #9

                    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.

                    Software Engineer
                    The Qt Company, Oslo

                    Z JoeCFDJ 2 Replies Last reply
                    1
                    • Axel SpoerlA Axel Spoerl

                      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.

                      Z Offline
                      Z Offline
                      zonman
                      wrote on last edited by zonman
                      #10

                      @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

                      1 Reply Last reply
                      0
                      • Axel SpoerlA Axel Spoerl

                        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.

                        JoeCFDJ Offline
                        JoeCFDJ Offline
                        JoeCFD
                        wrote on last edited by JoeCFD
                        #11

                        @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 SpoerlA 1 Reply Last reply
                        0
                        • JoeCFDJ JoeCFD

                          @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 SpoerlA Offline
                          Axel SpoerlA Offline
                          Axel Spoerl
                          Moderators
                          wrote on last edited by
                          #12

                          @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.

                          Software Engineer
                          The Qt Company, Oslo

                          JoeCFDJ 1 Reply Last reply
                          2
                          • Axel SpoerlA Axel Spoerl

                            @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.

                            JoeCFDJ Offline
                            JoeCFDJ Offline
                            JoeCFD
                            wrote on last edited by JoeCFD
                            #13

                            @Axel-Spoerl Got it. Thanks. I may have a peek into the source code and see how it is done.

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved