Можно ли изменить цвет ручки QSlider в соответствии с его положением?

Я довольно хорошо понял, как настроить QSlider с помощью таблиц стилей, но мне интересно, можно ли сделать следующее:

                                              введите описание изображения здесь

Мне бы хотелось, чтобы ручка ползунка сменила цвет с синего на желтый. Когда установлено слева, это синий; и когда вы переместите его вправо, он будет иметь градиент от синего до желтого.

Если это возможно через таблицы стилей, как? И если нет, как я могу реализовать это в paintEvent подкласса QSlider?

8

Решение

На самом деле вам не нужно делать что-то необычное, запас QSlider уже имеет valueChanged(int) сигнал, так что вы можете подключить его к функции, которая смешивает два цвета в зависимости от положения и устанавливает цвет стиля. Вот минимальный пример:

static QColor operator+(const QColor & a, const QColor & b) {
return QColor(a.red() + b.red(), a.green() + b.green(), a.blue() + b.blue());
}
static QColor operator*(const QColor & c, const qreal r) {
return QColor(c.red() * r, c.green() * r, c.blue() * r);
}

class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0) : QWidget(parent), from(248, 181, 20), to(64, 150, 214) {
auto l = new QHBoxLayout(this);
setLayout(l);
s = new QSlider(Qt::Horizontal, this);
s->setMinimum(0);
s->setMaximum(100);
l->addWidget(s);
connect(s, &QSlider::valueChanged, this, &Widget::colorize);
colorize(s->value());
}
private:
void colorize(int v) {
int d = s->maximum() - s->minimum();
v = v - s->minimum();
qreal rv = qreal(v) / d;
QColor c = from * rv + to * (1.0 - rv);
s->setStyleSheet(QString("QSlider::handle:horizontal {background-color: %1;}").arg(c.name()));
}
QSlider * s;
QColor from, to;
};

Это будет работать для любого диапазона и ориентации ползунка, код в основном находит относительное положение ручки в диапазоне от 0,0 до 1,0 и использует его для смешивания from а также to цвета, чтобы установить цвет ручки на соответствующее значение. Довольно странно, QColor не было операторов для умножения и сложения, что может пригодиться.

введите описание изображения здесь

Кроме того, вместо смешения двух цветов вы можете создать цвет в формате HSL, что даст вам немного другой градиент. изменения from/to от QColor с оттенками 42 и 202 соответственно вы можете:

QColor c = QColor::fromHsl(205 - (205 - 42) * rv, 200, 135);

Это даст вам цветовой оттенок для оттенка, а не для смешивания двух фиксированных цветов, что может быть более применимо в контексте температуры:

введите описание изображения здесь

Обратите внимание, что теперь посередине вы получаете цвет голубого цвета, а не «зомби» зеленый, и вы получаете чистый зеленый, прежде чем перейти к оранжевому цвету.

10

Другие решения

Я не верю, что вы можете сделать это, используя простую таблицу стилей. Но это легко выполнимо, специализируясь QSlider класс и применение соответствующей таблицы стилей, когда пользователь перемещает курсор (т.е. когда ValueChanged испускается).

Вот класс, который я написал, который делает свое дело. Он работает для горизонтального и вертикального курсора и может быть настроен для использования любого цвета. Это создает QImage из QLinearGradient чтобы сохранить карту цветов градиента, затем при изменении значения ползунка он извлекает соответствующий цвет из изображения на основе положения ползунка и применяет его через таблицу стилей.

Попытка сделать класс универсальным для повторного использования, но это может быть упрощено, если вам не нужно настраивать цвета и использовать только горизонтальные ползунки.

gradientslider.h:

#include <QSlider>
#include <QImage>
#include <QColor>

class GradientSlider : public QSlider
{
Q_OBJECT
public:
GradientSlider( QColor from, QColor to, Qt::Orientation orientation, QWidget* parent );

private slots:
void changeColor( int );

private:
QImage gradient;
};

gradientslider.cpp:

#include "gradientslider.h"#include <QLinearGradient>
#include <QPainter>

GradientSlider::GradientSlider( QColor from, QColor to, Qt::Orientation orientation, QWidget* parent ) :
QSlider( orientation, parent ),
gradient( QSize(100,100), QImage::Format_RGB32 )
{
// create linear gradient
QLinearGradient linearGrad( QPointF(0, 0), (orientation==Qt::Horizontal) ? QPointF(100, 0) : QPointF(0, 100) );
linearGrad.setColorAt(0, from);
linearGrad.setColorAt(1, to);

// paint gradient in a QImage:
QPainter p(&gradient);
p.fillRect(gradient.rect(), linearGrad);

connect( this, SIGNAL(valueChanged(int)), this, SLOT(changeColor(int)) );

// initialize
changeColor( value() );
}

void GradientSlider::changeColor( int pos )
{
QColor color;

if ( orientation() == Qt::Horizontal )
{
// retrieve color index based on cursor position
int posIndex = gradient.size().width() * ( pos - minimum() ) / (maximum() - minimum());
posIndex = std::min( posIndex, gradient.width() - 1 );

// pickup appropriate color
color = gradient.pixel( posIndex, gradient.size().height()/2 );
}
else
{
// retrieve color index based on cursor position
int posIndex = gradient.size().height() * ( pos - minimum() ) / (maximum() - minimum());
posIndex = std::min( posIndex, gradient.height() - 1 );

// pickup appropriate color
color = gradient.pixel( gradient.size().width()/2, posIndex );
}

// create and apply stylesheet!
// can be customized to change background and handle border!
setStyleSheet( "QSlider::handle:" + (( orientation() == Qt::Horizontal ) ? QString("horizontal"):QString("vertical")) + "{ \
border-radius: 5px; \
border: 2px solid #FFFFFF; \
width: 20px; \
margin: -5px 0;   \
background: " + color.name() + "}" );
}

Теперь просто сделайте:

QHBoxLayout* layout = new QHBoxLayout( this );
// horizontal slider:
layout->addWidget( new GradientSlider( QColor(79,174,231), QColor(251,192,22), Qt::Horizontal, this ) );
// or, vertical slider:
layout->addWidget( new GradientSlider( QColor(79,174,231), QColor(251,192,22), Qt::Vertical, this ) );

Цвета QColor(79,174,231) (~ синий) и QColor(251,192,22) (~ желтый) были взяты из изображения в исходном вопросе и могут быть заменены на Qt::blue, Qt::yellow (заканчивается немного другой окраской).

Это сделает это:

введите описание изображения здесь
введите описание изображения здесь
введите описание изображения здесь

4

По вопросам рекламы [email protected]