2016-10-19 5 views
8

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

                                                                                            enter image description here

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

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

+0

Глядя на пример QSlider (http://doc.qt.io/qt-4.8/stylesheet-examples.html#customizing-qslider), похоже, что использование qlineargradient может помочь вам в том, что вам нужно. – Chris

+0

@Chris 1. Пожалуйста, не указывайте ссылку на старую документацию. 2. Это даст градиент ** внутри ** рукоятки, а не градиент, следующий за движением. – IAmInPLS

+1

Извините, что я использую Qt 4 на своей работе, так что это документация, к которой я привык смотреть. Если это не сработает, в событии рисования найдите значение ползунка и используйте его для вычисления значения цвета rgb (линейное отношение от вашего начального к вашему концу может выглядеть нормально). Затем вы можете установить цвет в дескрипторе цвета с помощью таблицы стилей. Наконец вызовите обычное событие окраски QSlider. – Chris

ответ

10

На самом деле вы на самом деле не нужно делать ничего сверхъестественного, акции 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 не имел операторов для умножения и добавления, что может пригодиться.

enter image description here

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

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

Это даст вам цветую развертку для оттенка, а не смеси между двумя фиксированными цветами, которые могут быть более применимы в контексте температуры :

enter image description here

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

+0

Фантастический ответ! Я боялся использовать подкласс, но вы предоставили мне все, что мне нужно, чтобы иметь хороший слайдер! Спасибо, сэр :-) – IAmInPLS

+0

@IAmInPLS - спасибо, вам стоит подумать о переходе на QML, если вы хотите, чтобы пользовательский внешний вид чувствовал элементы gui. Практически тривиально делать это с нуля по сравнению с использованием стека QtWidget. – dtech

+0

Ну, я бы предпочел не отделять мой графический интерфейс от моей программной логики. Виджеты Qt достаточно хорошо документированы, на мой взгляд, плюс пользовательский интерфейс статичен, поэтому я дам QML позже, когда у меня есть время, чтобы правильно изучить его :-). – IAmInPLS

4

Я не верю, что вы можете сделать это, используя простую таблицу стилей. Но это легко сделать, специализируясь на классе 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 (заканчивая слегка отличающейся окраской).

Это будет делать это:

enter image description here enter image description here enter image description here

+0

Это действительно хороший ответ для подкласса, поэтому у вас есть мой upvote! Однако вы поймете, что я приму ответ, где мне просто нужно изменить таблицу стилей в слот :-). – IAmInPLS

+0

@IAmInPLS: Слот, помещенный в подкласс, может быть в любом классе. – jpo38

 Смежные вопросы

  • Нет связанных вопросов^_^