Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QSlider handle and QProxyStyle



  • By default, QSlider move his thumbtrack by a value belonging to the pageStep() prop on mouse click. To make thumbtrack jump directly at the mouse click point, we need to create a new class inherited by QSlider.

    .h

    #ifndef QIMPROVEDSLIDER_H
    #define QIMPROVEDSLIDER_H
    
    #include <QSlider>
    
    class QImprovedSlider : public QSlider
    {
        Q_OBJECT
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        void mouseReleaseEvent(QMouseEvent *event) override;
    public:
        explicit QImprovedSlider(QWidget *parent = 0);
    
    signals:
        void clicked(int value) const;
    
    };
    
    #endif // QIMPROVEDSLIDER_H
    

    .cpp

        #include <QWidget>
        #include <QMouseEvent>
        #include <QStyle>
        #include <QStyleOptionSlider>
        #include <QProxyStyle>
        #include "QImprovedSlider.h"
    
        class QImprovedSliderStyle : public QProxyStyle
        {
        public:
            using QProxyStyle::QProxyStyle;
            int styleHint(QStyle::StyleHint hint, const QStyleOption* option = 0,
                          const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const
            {
                if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
                    return (Qt::LeftButton | Qt::MidButton | Qt::RightButton);
                return QProxyStyle::styleHint(hint, option, widget, returnData);
            }
        };
    
        QImprovedSlider::QImprovedSlider(QWidget *parent) :
            QSlider(parent)
        {
            setStyle(new QImprovedSliderStyle(this->style()));
        }
    
    
        void QImprovedSlider::mousePressEvent(QMouseEvent *event) {
        QStyleOptionSlider opt;
        initStyleOption(&opt);
        QRect sr = style()->subControlRect(QStyle::CC_Slider,
                                           &opt,
                                           QStyle::SC_SliderHandle,
                                           this);
        qDebug() << sr.height() << sr.width();
        if (!sr.contains(event->pos()) && event->button() == Qt::LeftButton) {
            if (orientation() == Qt::Vertical)
                setValue(minimum() + ((maximum()-minimum()) * (height()-event->y())) / height() ) ;
            else
                setValue(minimum() + ((maximum()-minimum()) * event->x()) / width() ) ;
        }
        QSlider::mousePressEvent(event);
    }
    
    
        void QImprovedSlider::mouseReleaseEvent(QMouseEvent *event) {
            if (event->button() == Qt::LeftButton) {
                emit clicked(value());
                QSlider::mouseReleaseEvent(event);
            }
        }
    

    QImprovedSliderStyle make the handle drag more fluid, but in this way, the event is fired even when the click falls inside the handle, while the condition

    !sr.contains(event->pos())
    

    should avoid this.

    Can you help me?


  • Moderators

    @UnitScan
    alternatively you could "hack" a little bit.
    set the step size to 1 and max value to the widgets width. Update the max value on every resize (and also recalculate the value).
    You then create custom setter for your"real" max value and a new signal with the "real" value calculated linear to the base max value.


Log in to reply