【QT】自制控件---滚动选择器


因为我需要有连续的数字以供选择,所以只记了数字范围。如有需求可以改为用任意线性容器保持数据


代码:

self-contained.h

#ifndef SELFCONTAINED_H
#define SELFCONTAINED_H

#include <QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QPropertyAnimation>

#endif // SELFCONTAINED_H


rollingbox.h

#ifndef ROLLINGBOX_H
#define ROLLINGBOX_H

#include "self-contained.h"

class RollingBox : public QWidget//GIG_C_GOD
{
    Q_OBJECT
    Q_PROPERTY(int deviation READ readDeviation WRITE setDeviation)
public:
    explicit RollingBox(QWidget *parent = 0);

    void setRange(int min,int max);
    int readValue();
protected:
    int m_minRange;
    int m_maxRange;
    int m_currentValue;
    bool isDragging;
    int m_deviation;
    int m_mouseSrcPos;
    int m_numSize;//计算所得的数字字符尺寸,以最长的情况为准
    QPropertyAnimation *homingAni;

    void mousePressEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void paintEvent(QPaintEvent *);

    void paintNum(QPainter &painter,int num,int deviation);
    void homing();
    int readDeviation();
    void setDeviation(int n);
signals:
    void currentValueChanged(int value);
    void deviationChange(float deviation);
public slots:

};

#endif // ROLLINGBOX_H

rollingbox.cpp

#include "rollingbox.h"

RollingBox::RollingBox(QWidget *parent) :
    QWidget(parent),m_minRange(0),m_maxRange(100),
    m_currentValue(50),isDragging(0),m_deviation(0),m_numSize(6)
{
    homingAni  = new QPropertyAnimation(this,"deviation");
    homingAni->setDuration(300);
    homingAni->setEasingCurve(QEasingCurve::OutQuad);
}

void RollingBox::setRange(int min,int max)
{
    m_minRange = min;
    m_maxRange = max;

    if(m_currentValue < min)
        m_currentValue = min;
    if(m_currentValue > max)
        m_currentValue = max;

    //计算字符尺寸
    m_numSize = 3;
    int temp = m_maxRange;
    while(temp > 0)
    {
        temp /= 10;
        m_numSize++;
    }

    repaint();
}

int RollingBox::readValue()
{
    return m_currentValue;
}

void RollingBox::mousePressEvent(QMouseEvent *e)
{
    homingAni->stop();
    isDragging = 1;
    m_mouseSrcPos = e->pos().x();
}

void RollingBox::mouseMoveEvent(QMouseEvent *e)
{
    if(isDragging)
    {
        //数值到边界时,阻止继续往对应方向移动
        if((m_currentValue == m_minRange && e->pos().x() >= m_mouseSrcPos)||
          (m_currentValue == m_maxRange && e->pos().x() <= m_mouseSrcPos))
            return;

        m_deviation = e->pos().x() - m_mouseSrcPos;

        //若移动速度过快时进行限制
        if(m_deviation > (width()-1)/4)
            m_deviation = (width()-1)/4;
        else if(m_deviation < -(width()-1)/4)
            m_deviation = -(width()-1)/4;

        emit deviationChange((float)m_deviation/((width()-1)/4));

        repaint();
    }
}

void RollingBox::mouseReleaseEvent(QMouseEvent *)
{
    if(isDragging)
    {
        isDragging = 0;
        homing();
    }
}

void RollingBox::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    int Width = width()-1;
    int Height = height()-1;

    if(m_deviation >= Width/4 && m_currentValue > m_minRange)
    {
        m_mouseSrcPos += Width/4;
        m_deviation -= Width/4;
        m_currentValue -= 1;
    }
    if(m_deviation <= -Width/4 && m_currentValue < m_maxRange)
    {
        m_mouseSrcPos -= Width/4;
        m_deviation += Width/4;
        m_currentValue += 1;
    }

    //中间数字
    paintNum(painter,m_currentValue,m_deviation);

    //两侧数字1
    if(m_currentValue != m_minRange)
        paintNum(painter,m_currentValue-1,m_deviation-Width/4);
    if(m_currentValue != m_maxRange)
        paintNum(painter,m_currentValue+1,m_deviation+Width/4);

    //两侧数字2,超出则不显示
    if(m_deviation >= 0 && m_currentValue-2 >= m_minRange)
        paintNum(painter,m_currentValue-2,m_deviation-Width/2);
    if(m_deviation <= 0 && m_currentValue+2 <= m_maxRange)
        paintNum(painter,m_currentValue+2,m_deviation+Width/2);

    //边框
    painter.setPen(QPen(QColor(0,0,0,120),2));
    painter.drawLine(Width/8*3,0,Width/8*3,Height);
    painter.drawLine(Width/8*5,0,Width/8*5,Height);
}

void RollingBox::paintNum(QPainter &painter,int num,int deviation)
{
    int Width = width()-1;
    int Height = height()-1;

    int size = (Width - qAbs(deviation))/m_numSize;
    int transparency = 255-510*qAbs(deviation)/Width;
    int width = Width/2-3*qAbs(deviation)/4;
    int x = Width/2+deviation-width/2;

    QFont font;
    font.setPixelSize(size);
    painter.setFont(font);
    painter.setPen(QColor(0,0,0,transparency));
    painter.drawText(QRectF(x,0,width,Height),
                     Qt::AlignCenter,
                     QString::number(num));
}

void RollingBox::homing()
{
    //将数字矫正到中心
    if(m_deviation > width()/8)
    {
        homingAni->setStartValue((width()-1)/8-m_deviation);
        homingAni->setEndValue(0);
        m_currentValue--;
    }
    else if(m_deviation > -width()/8)
    {
        homingAni->setStartValue(m_deviation);
        homingAni->setEndValue(0);
    }
    else if(m_deviation < -width()/8)
    {
        homingAni->setStartValue(-(width()-1)/8-m_deviation);
        homingAni->setEndValue(0);
        m_currentValue++;
    }
    emit currentValueChanged(m_currentValue);
    homingAni->start();
}

int RollingBox::readDeviation()
{
    return m_deviation;
}

void RollingBox::setDeviation(int n)
{
    m_deviation = n;
    repaint();
}


评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值