How to draw a picture instead of the slider of a QSlider?

1.9k Views Asked by At

I have created a class that inherits from QSlider and I want to draw a picture on the slider (grabber) instead of showing the plain one.

How to do it?

3

There are 3 best solutions below

0
On BEST ANSWER

You can do it into the paintEvent method of the widget. This allows you to redraw all or only a part of the widget.

0
On

Answer provided by Viet:

void InheritedSlider::paintEvent(QPaintEvent *event)
{
    // uncomment to draw the parent first. Comment out to just ignore it.
    //QSlider::paintEvent(event);
    
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    
    //painter.translate(width() / 2, height() / 2);
    //painter.scale(100 / 200.0, 100 / 200.0);
    
    QPainterPath volPath;
    volPath.moveTo(60.0, 40.0);
    volPath.arcTo(20.0, 20.0, 40.0, 40.0, 0.0, 360.0);
    volPath.moveTo(40.0, 40.0);
    volPath.lineTo(40.0, 80.0);
    volPath.lineTo(80.0, 80.0);
    volPath.lineTo(80.0, 40.0);
    volPath.closeSubpath();
    painter.drawPath(volPath);
}
0
On

A combination of stylesheets and paintEvent could be used to customize the handle, without reimplementing mouse events.

If the drawing area exceeds the handle's geometry, it will not pick up mouse clicks, therefore I'm using stylesheets to make it the same size as the area being drawn.

Here's an example that widens the handle and makes it a rounded rect, to adjusted it, it's needed to modify both stylesheets and paintEvent:

#include <QApplication>
#include <QtWidgets>

class MSlider : public QSlider
{
public:
    QRect handleRect;
    MSlider(QWidget *parent = nullptr)
    {
        setStyleSheet("QSlider"
                      "{"
                          "width: 52px;"
                      "}"
                      "QSlider::groove:vertical "
                      "{"
                          //border and width are necessary
                          //adjust them with care
                          "border: 1px;"
                          "width: 5px;"
                          "background: white;"
                      "}"
                      "QSlider::add-page:vertical "
                      "{"
                          "background: white;"
                      "}"
                      "QSlider::sub-page:vertical "
                      "{"
                          "background: green;"
                      "}"
                      "QSlider::handle:vertical "
                      "{"
                          "height: 24px;"
                          //width does not make a difference 
                          //use margin instead to control width
                          "margin: -1px -24px;"
                      "}");
    }
protected:
    void paintEvent(QPaintEvent *event) override
    {
        //paint the slider before painting your custom handle or it might cover it
        QSlider::paintEvent(event);

        QPainter painter(this);
        painter.setRenderHints(QPainter::Antialiasing);

        QStyleOptionSlider opt;
        initStyleOption(&opt);

        //get handle rect
        //use qDebug to check it when adjusting stylesheet 
        handleRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);

        painter.setBrush(Qt::black);
        painter.setPen(Qt::black);
        painter.drawRoundedRect(handleRect, 5, 5);
    }
};

int main(int argc,char*argv[])
{
    QApplication a(argc, argv);

    MSlider slider;

    slider.show();

    return a.exec();
}

Result:

Custom slider handle being dragged


Note: This solution is not tested on horizontal sliders.


For more: