是否可以根据其位置更改 QSlider 手柄的颜色?
Is it possible to change the color of a QSlider's handle according to its position?
我非常了解如何通过样式表自定义 QSlider,但我想知道是否可以执行以下操作:
我希望滑块的手柄从蓝色变为黄色。当设置在左边时,它是蓝色的;当你把它向右移动时,它会有一个从蓝色到黄色的渐变。
如果可以通过样式表实现,怎么做?如果不行,我如何在 QSlider 的子类的 paintEvent 中实现它?
我不相信你可以使用简单的样式来做到这一点 sheet。但这很容易通过专门化 QSlider
class 并在用户移动光标时应用适当的样式 sheet 来实现(即:当 valueChanged 被发出时)。
这是我写的 class 可以解决问题的方法。它适用于水平和垂直光标,可以自定义使用任何颜色。它创建一个 QImage from a QLinearGradient 来存储渐变色图,然后,当滑块值发生变化时,它会根据滑块的位置从图像中提取适当的颜色并通过样式应用它 sheet.
尝试使 class 通用以实现可重用性,但如果您不需要自定义颜色并且只使用水平滑块,则可以简化它。
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)
(~黄色)是从原始问题 post 中的图像中提取的,可以用 Qt::blue
替换, Qt::yellow
(颜色略有不同)。
这样做就可以了:
实际上你真的不需要做任何花哨的事情,股票 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);
这将为您提供色调的颜色扫描,而不是混合两种固定颜色,这可能更适用于温度环境:
请注意,现在中间的颜色是青色而不是 "zombie" 绿色,在到达橙色之前先穿过干净的绿色。
我非常了解如何通过样式表自定义 QSlider,但我想知道是否可以执行以下操作:
我希望滑块的手柄从蓝色变为黄色。当设置在左边时,它是蓝色的;当你把它向右移动时,它会有一个从蓝色到黄色的渐变。
如果可以通过样式表实现,怎么做?如果不行,我如何在 QSlider 的子类的 paintEvent 中实现它?
我不相信你可以使用简单的样式来做到这一点 sheet。但这很容易通过专门化 QSlider
class 并在用户移动光标时应用适当的样式 sheet 来实现(即:当 valueChanged 被发出时)。
这是我写的 class 可以解决问题的方法。它适用于水平和垂直光标,可以自定义使用任何颜色。它创建一个 QImage from a QLinearGradient 来存储渐变色图,然后,当滑块值发生变化时,它会根据滑块的位置从图像中提取适当的颜色并通过样式应用它 sheet.
尝试使 class 通用以实现可重用性,但如果您不需要自定义颜色并且只使用水平滑块,则可以简化它。
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)
(~黄色)是从原始问题 post 中的图像中提取的,可以用 Qt::blue
替换, Qt::yellow
(颜色略有不同)。
这样做就可以了:
实际上你真的不需要做任何花哨的事情,股票 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);
这将为您提供色调的颜色扫描,而不是混合两种固定颜色,这可能更适用于温度环境:
请注意,现在中间的颜色是青色而不是 "zombie" 绿色,在到达橙色之前先穿过干净的绿色。