Reputation: 53
I'm trying to build a progressbar like this:
The problem is that when the value is below a certain percentage, it is shown this way:
Now, I know this is a known bug of the application of stylesheets and the only way to escape this is subclassing the QProgressBar class and overriding the paintEvent method. I tried to do this using the suggestions found here progressbar is incorrect displayed but it doesn't work for me. Implementing this in C++ I get a progressbar that is always filled, even if the gradient is applied:
Here I post my QtprogressBar class redefinition
Header file:
#ifndef COLOREDPROGRESSBAR_H
#define COLOREDPROGRESSBAR_H
#include <QWidget>
#include <QProgressBar>
#include <QPaintEvent>
class ColoredProgressBar : public QProgressBar
{
Q_OBJECT
public:
explicit ColoredProgressBar(QWidget *parent = 0);
~ColoredProgressBar();
protected:
void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
signals:
public slots:
};
#endif // COLOREDPROGRESSBAR_H
Cpp File
#include "ColoredProgressbar.h"
#include <QStyleOptionProgressBar>
#include <QStyle>
#include <QStylePainter>
#include <algorithm>
#include <QWidget>
ColoredProgressBar::ColoredProgressBar(QWidget *parent) : QProgressBar(parent)
{
}
ColoredProgressBar::~ColoredProgressBar()
{
}
void ColoredProgressBar::paintEvent(QPaintEvent*)
{
QStylePainter painter(this);
QStyleOptionProgressBar *opt = new QStyleOptionProgressBar();
this->initStyleOption(opt);
QRect rect = this->style() >subElementRect(QStyle::SE_ProgressBarContents, opt, this);
int min_size = rect.width();
int groove_size = rect.height() - min_size - 1;
double value_range = this->maximum() - this->minimum();
double offset = this->value() / value_range * groove_size;
double new_value = (min_size + 1 + offset) / (rect.height() * value_range);
if ((int)new_value != new_value)
{
new_value = std::min((double)this->maximum(), new_value + 1);
}
opt->progress = new_value;
painter.drawControl(QStyle::CE_ProgressBar, *opt);
}
MainWindow
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ColoredProgressbar.h"
#include "ProgressBar.cpp"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QWidget *progressWidget = new QWidget;
layout = new QGridLayout(progressWidget);
progress = new ColoredProgressBar(this);
progress->setOrientation(Qt::Vertical);
progress->setRange(0, 100);
progress->setFixedSize(50, 300);
progress->setTextVisible(true);
QString value1 = "QProgressBar {border-radius: 25px};";
progress->setStyleSheet(value1);
layout->addWidget(progress,0, 1);
this->setCentralWidget(progressWidget);
slider = new QSlider(this);
slider->setFixedSize(300, 400);
slider->setMaximum(100);
slider->setMinimum(0);
QObject::connect(slider, &QSlider::valueChanged, this, &MainWindow::setProgressValue);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setProgressValue()
{
progress->setValue(slider->value());
QString value1 = "QProgressBar {border-radius: 25px} QProgressBar::chunk {background: QLinearGradient(x1: 0, y1: 1, x2: 0, y2: 0,stop: 0 #5ea9d8, stop: 0.30 #439bd1 ,stop: 0.4999 #6eb1dc, stop: 1 #6cb0db ); border-radius: 25px;}";
QString value2 = "QProgressBar {border-radius: 25px} QProgressBar::chunk {background: QLinearGradient(x1: 0, y1: 1, x2: 0, y2: 0,stop: 0 #5ea9d8, stop: 0.30 #439bd1 ,stop: 0.4999 #6eb1dc, stop: 0.8 #6cb0db ,stop: 1 #F0F150 ); border-radius: 25px;}";
QString value3 = "QProgressBar {border-radius: 25px} QProgressBar::chunk {background: QLinearGradient(x1: 0, y1: 1, x2: 0, y2: 0,stop: 0 #5ea9d8, stop: 0.30 #439bd1 ,stop: 0.4999 #6eb1dc, stop: 0.6 #6cb0db ,stop: 0.8 #F0F150, stop: 1 #ca3142 ); border-radius: 25px;}";
if(progress->value()<=50)
{
progress->setStyleSheet(value1);
}
else if(progress->value()>50 && progress->value()<80)
{
progress->setStyleSheet(value2);
}
else if(progress->value()>=80)
{
progress->setStyleSheet(value3);
}
}
Upvotes: 2
Views: 895
Reputation: 3469
Note that the Python example you ported to C++ is for a horizontal progressbar whereas you draw a vertical progressbar. Therefore width()
and height()
need to be swapped.
If you want your class to be able to work for both orientations you can use QProgressBar::orientation() and adapt the calculation based on its result.
Furthermore you want to check your data types. Unlike in C++ in Python every division yields a float value, so take a look at Why does dividing two int not yield the right value when assigned to double? and adapt your code accordingly, i.e. like this:
double value_range = this->maximum() - this->minimum();
double offset = this->value() / value_range * groove_size;
double new_value = (min_size + 1 + offset) / rect.width() * value_range;
if ((int)new_value != new_value)
{
new_value = std::min(this->maximum(), new_value + 1);
}
Upvotes: 1