QSlider handle and QProxyStyle

428 views Asked by At

By default, QSlider moves its handle by a value belonging to the pageStep() property on mouse click. To make the handle 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.

0

There are 0 answers