QSlider跳转,拖动优化

 

QSlider默认是点击一下步进一格,handle块很小的时候还拖不准,在播放器等页面使用就不太友好,不能直接跳转到想要的位置,特此进行改进,继承QSlider,实现点哪跳转至哪, 点击任意处都可进行拖动,对水平滑动条及垂直滑动条进行了适配;

废话不多说,直接上代码:

CSlider.h

#pragma once

#include <QSlider>


//自定义滑块类  实现类似安卓滑动条功能, 任意点击跳转 及 任意拖选
//滑动条为垂直时候, 请设置滑块handle为滑动条宽度的一半 否则可能出现点击不太准现象
//滑动条为水平时候, 请设置滑块handle为滑动条高度的一半
class CSlider : public QSlider {
    Q_OBJECT
public:
    //handleLen  0 为默认, 垂直slider:handle的高度 / 2, 水平slider: handle的宽度 / 2, 若设置了则以此值计算slider值偏移量
    CSlider(QWidget *parent = nullptr, uint16_t handleLen = 0);
    ~CSlider();
    //设置值 , bool bNotify 是否需要信号通知
    void SetSliderValue(int val, bool bNotify = false);

protected:
    //鼠标按下
    virtual void mousePressEvent(QMouseEvent * event);
    //鼠标拖动
    virtual void mouseMoveEvent(QMouseEvent * event);
    //鼠标松开
    virtual void mouseReleaseEvent(QMouseEvent * event);

private:
    //鼠标位置转换成滑动条的值
    int32_t MousePostionToSliderVal(const QPoint & pos);
//signals:

private:
    uint16_t m_handleLen; //滑块宽度
};

 

CSlider.cpp


#include "CSlider.h"

#include <QSlider>
#include <QLabel>
#include <QStyle>

#ifdef Q_OS_WIN
#pragma execution_character_set("utf-8")
#endif

CSlider::CSlider(QWidget * parent, uint16_t handleLen)
    : QSlider(parent), m_handleLen(handleLen) {
}

CSlider::~CSlider() {

}
//设置值 , bool bNotify 是否需要信号通知值滑块移动了
void CSlider::SetSliderValue(int val, bool bNotify) {
    setSliderPosition(val);
    if (bNotify)
        emit sliderMoved(val);
}

void CSlider::mousePressEvent(QMouseEvent * event) {
    if (event->button() != Qt::LeftButton)
        return;
    setSliderDown(true);
}

static bool bIsMove = false;
void CSlider::mouseMoveEvent(QMouseEvent * event) {
    bIsMove = true;
    int32_t pos = MousePostionToSliderVal(event->pos());
    if (pos != sliderPosition()) {
        setSliderPosition(pos);
        emit sliderMoved(pos);
    }
}

void CSlider::mouseReleaseEvent(QMouseEvent * event) {
    setSliderDown(false);
    if (!isEnabled() || event->button() != Qt::LeftButton) {
        bIsMove = false;
        return;
    }

    if (bIsMove) {
        QSlider::mouseReleaseEvent(event);
        bIsMove = false;
    } else {
        int32_t pos = MousePostionToSliderVal(event->pos());
        if (pos != sliderPosition()) {
            setSliderPosition(pos);
            emit sliderMoved(pos);
        }
    }
}

//鼠标位置转换成滑动条的值 
int32_t CSlider::MousePostionToSliderVal(const QPoint & pos) {
    int32_t duration = maximum() - minimum();
    int32_t sliderPos = 0;
    qreal mousePos = 0;
    uint16_t hanleLen = 0;
    if (Qt::Vertical == orientation()) {
        //设置了handle高度  则以m_handleLen为准, 如无设置 则以宽度一半为handleLen
        hanleLen = m_handleLen ? m_handleLen : width() / 2.0;
        mousePos = (qreal)(pos.y() - hanleLen / 2);
        if (0 > mousePos)
            mousePos = 0;
        else if (mousePos > height() - hanleLen)
            mousePos = (qreal)(height() - hanleLen);
        sliderPos = maximum() - duration * (mousePos / (height() - hanleLen));
    } else {
        //设置了handle宽度  则以m_handleLen为准, 如无设置 则以高度度一半为handleLen
        hanleLen = m_handleLen ? m_handleLen : height() / 2.0;
        mousePos = (qreal)(pos.x() - hanleLen / 2);
        if (0 > mousePos)
            mousePos = 0;
        else if (mousePos > width() - hanleLen)
            mousePos = (qreal)(width() - hanleLen);
        sliderPos = minimum() + duration * (mousePos / (width() - hanleLen));
    }
    return sliderPos;
}

使用:

CSlider * m_pSlider;

m_pSlider = new CSlider(this, 25);
m_pSlider->setFixedSize(60, 480);
m_pSlider->setContentsMargins(0, 0, 0, 0);
m_pSlider->setOrientation(Qt::Vertical);
m_pSlider->setRange(100, 200);
m_pSlider->setSingleStep(1);
m_pSlider->setValue(100);
m_pSlider->setTickPosition(QSlider::TicksBothSides);

使用方法和QSlider并无多大区别;

有个值得注意的地方,构造函数第二个参数, handLen为滑块大小,需配合QSS handle:vertical->height属性 或 handle:horizontal ->width属性结合使用,以此进行偏移计算sliderpostion位置

附上QSS供参考:

QSlider#CSlider::groove:horizontal{
    background:#4b4b4b;
    height:6px;
    border-radius:5px;
}
QSlider#CSlider::add-page:horizontal{
    background:#c5c5c5;
    height:6px;
    border-radius:5px;
}
QSlider#CSlider::sub-page:horizontal{
    background:rgba(2, 183, 196, 0.75);
    height:6px;
    border-radius:5px;
}
QSlider#CSlider::handle:horizontal{
    width:25px;
    margin-top: -17px;
    margin-bottom: -17px;
    border-radius: 5px;
    background: rgba(255, 255, 255, 0.85);
}
QSlider#CSlider::handle:horizontal:pressed, QSlider#CSlider::handle:horizontal:hover{
    width:25px;
    border-radius:5px;
    background: #FFFFFF;
}
QSlider#CSlider::add-page:horizontal:disabled{
    background:#616161;
}
QSlider#CSlider::sub-page:horizontal:disabled{
    background:rgba(141, 141, 141, 0.75);
}
QSlider#CSlider::handle:horizontal:disabled{
    background: rgba(112, 112, 112, 0.85);
}

 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值