Qt如何自定义滑动条

最近要用到滑动条,Qt自带的QSlider虽然能满足需求,但是操作起来有很多不舒服的地方,于是在它的基础上改了改,分享给大家使用。

先放效果图

silder

在QSlider的基础上,改变了样式,绘制了刻度,增加了取整功能,只需要微调就能适应各种需求。

1、头文件

需要包含下面的东西

#include 
#include 
#include 
#include 
#include 

2、声明

需要继承QSlider,并重写两个鼠标事件mousePressEvent和mouseReleaseEvent,使用paintEvent用来绘制刻度线,使用信号发送选中的数值。

class MySlider : public QSlider
{
    Q_OBJECT
public:
    MySlider(QWidget *parent = nullptr);
    ~MySlider();

signals:
    void sliderValue(float);

private:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *ev);
};

3、构造函数

首先在构造函数中配置控件的相关属性,在此宏定义的几个数值:nMin和nMax代表取值范围,nSingleStep代表步长,nTick代表刻度间隔,nWidth和nHeight控制控件的大小。

通过设置Orientation为Horizontal,使控件为横向。

#include "myslider.h"

int nMin = 0;
int nMax = 100;
int nSingleStep = 10;
int nTick = 10;     //修改刻度个数改此数值
int nWidth = 200;
int nHeight = 50;

MySlider::MySlider(QWidget *parent):
    QSlider (parent)
{
    setOrientation(Qt::Horizontal);
    setFixedSize(nWidth,nHeight);
    setMinimum(nMin);
    setMaximum(nMax);
    setSingleStep(nSingleStep);
    setTickInterval(nTick);
    setTickPosition(QSlider::TicksAbove);

4、设置样式表

QSlider::groove控制背景样式,QSlider::handle控制滑块样式,QSlider::sub-page控制划过区域的样式。

需要注意的是,qss和QSlider自带的刻度线并不兼容,使用qss就不能显示自带的刻度线了,但是后文我提供了解决方法。

setStyleSheet("QSlider::groove:horizontal{height:12px; left:0px; right:0px; border:0px; border-radius:6px; background:rgb(242,242,242);}    \
               QSlider::handle:horizontal{width:24px; background:#1644B0; border-radius:12px; margin:-6px 0px;}  \
               QSlider::sub-page:horizontal{background:#4C85FB; border:0px; border-radius:6px;}");
}

5、重写鼠标点击事件

之所以要这么做,是因为QSlider的点击效果是一格一格地移动,我希望滑块能直接跳到指定位置,所以需要用到setValue。

void MySlider::mousePressEvent(QMouseEvent * event)
{
    int pointPos = ((double)event->pos().x()) / (this->width() * (nMax - nMin) + nMin);
    if(pointPos != 0){
        if(abs(pointPos - this->value()) > nTick){
            this->setValue(pointPos);
        }
    }
    else{
        QSlider::mousePressEvent(event);
    }
}

6、重写鼠标释放事件

因为希望取值可以取几个固定的值,此处限定只能取0, 0.1, 0.2… 1这些值,所以在释放时对当前值四舍五入,然后让滑块移动到相应的位置。最后发出信号传递数值。

void MySlider::mouseReleaseEvent(QMouseEvent *event)
{
    //获取当前点击位置
    int currentX = event->pos().x();

    //获取当前点击的位置占整个Slider的百分比
    float per = currentX *1.0 /this->width();

    //限制边界
    if(per > 1) per = 1;
    else if(per < 0) per = 0;

    //按步长取整
    per = (float)(qRound(per * 100 / nTick) * nTick) / 100;

    //利用算得的百分比得到具体数字
    int value = per*(this->maximum() - this->minimum()) + this->minimum();

    //设定滑动条位置
    this->setValue(value);

    //滑动条移动事件等事件也用到了mousePressEvent,加这句话是为了不对其产生影响,是的Slider能正常相应其他鼠标事件
    QSlider::mousePressEvent(event);

    emit sliderValue(per);
}

7、绘制刻度

前文提到了qss和QSlider刻度的冲突,所以这里我们直接使用paintEvent画线。

修改宏定义的参数值,刻度的数量也会随之变动。

void MySlider::paintEvent(QPaintEvent *)
{
    QStylePainter p(this);
    QStyleOptionSlider opt;
    initStyleOption(&opt);

    // 获取滑块的大小
    QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);

    // draw tick marks
    // do this manually because they are very badly behaved with style sheets
    int interval = tickInterval();
    if (interval == 0)
    {
        interval = pageStep();
    }

    if (tickPosition() != NoTicks)
    {
        for (int i = minimum(); i <= maximum(); i += interval)
        {
            int x = round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) * (double)(this->width() - handle.width()) + (double)(handle.width() / 2.0))) - 1;
            int h = 4;
            p.setPen(QColor("#a5a294"));
            if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
            {
                int y = this->rect().top();
                p.drawLine(x, y, x, y + h);
            }
            if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
            {
                int y = this->rect().bottom();
                p.drawLine(x, y, x, y - h);
            }
    }
        }
    // draw the slider (this is basically copy/pasted from QSlider::paintEvent)
    opt.subControls = QStyle::SC_SliderGroove;
    p.drawComplexControl(QStyle::CC_Slider, opt);
    // draw the slider handle
    opt.subControls = QStyle::SC_SliderHandle;
    p.drawComplexControl(QStyle::CC_Slider, opt);
}

8、实际使用

拖动或点击滑动条都会发出信号,传递滑块对应的值。

所以在要使用的地方建立信号槽,就可以接收对应滑动条传来的值并加以处理。

FaceThreshSlider = new MySlider(this);
connect(FaceThreshSlider, SIGNAL(sliderValue(float)), this, SLOT(setSlideThresh(float)));

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

你可能感兴趣的:(Qt如何自定义滑动条)