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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.