Можно ли изменить цвет ручки QSlider в соответствии с ее положением?
Я довольно хорошо понял, как настроить QSlider через таблицы стилей, но мне интересно, можно ли сделать следующее:
Я бы хотел, чтобы ручка слайдера перешла от синего к желтому. Когда он установлен слева, он синий; и когда вы перемещаете его вправо, он будет иметь градиент от синего до желтого.
если это возможно через таблицы стилей, как? и если нет, то как я могу реализовать это в paintEvent подкласса QSlider?
2 ответов
на самом деле вам не нужно делать ничего необычного, запас 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);
это даст вам цвет развертки для оттенка, а не смешивать между двумя фиксированными цветами, которые могут быть более применимы в контексте температуры:
обратите внимание, что теперь в середине вы получаете голубой цвет, а не" зомби " зеленый, и вы получаете через чистый зеленый, прежде чем добраться до оранжевого.
Я не верю, что вы можете сделать это с помощью простой таблицы стилей. Но это легко выполнимо, специализирующихся QSlider
class и применение соответствующей таблицы стилей, когда пользователь перемещает курсор (i.e: когда 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() + "}" );
}
теперь просто do:
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
(заканчивая немного другой окраской).
это сделает это: