qt循环滑动选择功能

想做个循环滑动选择控件,于是在网上找了相应的代码如下链接:【QT】自制控件---滚动选择器_BIG_C_GOD的博客-CSDN博客

这个滑动选择控件只是滑到尽头就滑不动了,于是做了改进做成循环滑动控件,代码如下:

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <rollingbox.h>

namespace Ui {
class MainWidget;
}

class MainWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MainWidget(QWidget *parent = nullptr);
    ~MainWidget();

private:
    Ui::MainWidget *ui;
    RollingBox * m_yearRolling;
    RollingBox * m_monthRolling;
    RollingBox * m_dayRolling;
};

#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include "ui_mainwidget.h"

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWidget)
{
    ui->setupUi(this);
    m_yearRolling = new RollingBox(this);
    //m_yearRolling->resize(60, 100);
    m_yearRolling->setDirection(RollingBox::SD_HORIZONTAL);
    m_yearRolling->setRange(0, 10);
    m_yearRolling->setValue(9);
    m_yearRolling->move(50, 50);

    m_monthRolling = new RollingBox(this);
    m_monthRolling->setDirection(RollingBox::SD_VERTICAL);
    m_monthRolling->setRange(1, 12);
    m_monthRolling->setValue(11);
    m_monthRolling->resize(60, 100);
    m_monthRolling->move(120, 100);
}

MainWidget::~MainWidget()
{
    delete ui;
}

rollingbox.h

#ifndef ROLLINGBOX_H
#define ROLLINGBOX_H

#include <QObject>
#include <QWidget>
#include <QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QDebug>
#include <QPropertyAnimation> //qt动画类


class RollingBox : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(int deviation READ readDeviation WRITE setDeviation)

public:
    enum ShowDirection{
        SD_HORIZONTAL,
        SD_VERTICAL
    };
    explicit RollingBox(QWidget *parent = nullptr);

    void setRange(int min,int max);
    void setDirection(ShowDirection dir);
    int getValue(void) { return m_currentValue; }
    void setValue(int value);

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

signals:
    void currentValueChanged(int value);
    void deviationChange(float deviation);

private:
    void paintNum(QPainter &painter,int num,int deviation);
    void paintLine(QPainter &painter);
    void homing(void);
    int readDeviation(void);
    void setDeviation(int n);

private:
    int m_minRange;
    int m_maxRange;
    int m_currentValue;
    ShowDirection m_showDirection;
    bool isDragging;
    int m_deviation;
    int m_mouseSrcPos;
    int m_numSize;//计算所得的数字字符尺寸,以最长的情况为准
    QPropertyAnimation *homingAni;
};

#endif // ROLLINGBOX_H

rollingbox.cpp (关健代码)

#include "rollingbox.h"

RollingBox::RollingBox(QWidget *parent) : QWidget(parent),
    m_minRange(0),
    m_maxRange(100),
    m_currentValue(50),
    m_showDirection(SD_HORIZONTAL),
    isDragging(false),
    m_deviation(0),
    m_mouseSrcPos(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();
}

void RollingBox::setDirection(RollingBox::ShowDirection dir)
{
    m_showDirection = dir;
    repaint();
}

void RollingBox::setValue(int value)
{
    if (value > m_maxRange)
        value = m_maxRange;
    if (value < m_minRange)
        value = m_minRange;
    m_currentValue = value;
}

/*
 * 鼠标按住事件
 */
void RollingBox::mousePressEvent(QMouseEvent *e)
{
    homingAni->stop();
    isDragging = true;
    m_mouseSrcPos = (m_showDirection == SD_HORIZONTAL)? (e->pos().x()):(e->pos().y());
}

/*
 * 鼠标移动事件
 */
void RollingBox::mouseMoveEvent(QMouseEvent *e)
{
    if(!isDragging)
        return ;

    int pos = (m_showDirection == SD_HORIZONTAL)? (e->pos().x()) : (e->pos().y());
    int length = (m_showDirection == SD_HORIZONTAL)? (width()) : (height());

    m_deviation = pos - m_mouseSrcPos;

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

    emit deviationChange((float)m_deviation / ((length - 1) / 4));
    repaint();
}

/*
 * 鼠标松开事件
 */
void RollingBox::mouseReleaseEvent(QMouseEvent *)
{
    if(!isDragging)
        return ;
    isDragging = false;
    homing();
}

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

    int measurement = (m_showDirection == SD_HORIZONTAL)? (width()-1) : (height()-1);

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

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

    //两侧数字1
    int temp = m_currentValue - 1;
    if (temp < m_minRange)
        temp = m_maxRange;
    paintNum(painter, temp, m_deviation - measurement / 4);
    temp = m_currentValue + 1;
    if (temp > m_maxRange)
        temp = m_minRange;
    paintNum(painter, temp, m_deviation + measurement / 4);

    //两侧数字2,超出则不显示
    if(m_deviation >= 0)
    {
        temp = m_currentValue - 2;
        if (temp == m_minRange - 1)
            temp = m_maxRange;
        else if (temp == m_minRange - 2)
            temp = m_maxRange - 1;
        else if (temp < m_minRange)
            temp = m_maxRange - 2;
        paintNum(painter, temp, m_deviation - measurement / 2);
    }
    if(m_deviation <= 0)
    {
        temp = m_currentValue + 2;
        if (temp == m_maxRange + 1)
            temp = m_minRange;
        else if (temp == m_maxRange + 2)
            temp = m_minRange + 1;
        else if (temp > m_maxRange)
            temp = m_minRange + 2;
        paintNum(painter, temp, m_deviation + measurement / 2);
    }

    //边框
    paintLine(painter);
}

/*
 * 绘制数字
 */
void RollingBox::paintNum(QPainter &painter,int num,int deviation)
{
    painter.save();

    int measurement = (m_showDirection == SD_HORIZONTAL)? (width()-1) : (height()-1);

    int size = (measurement - qAbs(deviation)) / m_numSize;
    //颜色透明度
    int transparency = 255 - 510 * qAbs(deviation) / measurement;
    int len = measurement / 2 - 3 * qAbs(deviation) / 4;
    int pos = measurement / 2 + deviation - len / 2;

    QFont font;
    font.setPixelSize(size);
    painter.setFont(font);
    painter.setPen(QColor(0, 0, 0, transparency));

    if (m_showDirection == SD_HORIZONTAL)
        painter.drawText(QRectF(pos, 0, len, height()-1), Qt::AlignCenter, QString::number(num));
    else
        painter.drawText(QRectF(0, pos, width()-1, len), Qt::AlignCenter, QString::number(num));

    painter.restore();
}

/*
 * 画线
 */
void RollingBox::paintLine(QPainter &painter)
{
    painter.save();

    QPen pen;
    pen.setBrush(QColor(0, 0, 0, 120));
    pen.setWidth(4);
    pen.setCapStyle(Qt::RoundCap);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);

    int space = 10;
    if(m_showDirection == SD_HORIZONTAL)
    {
        int up_down_space = height() / 10;
        QPoint left_up=QPoint(space + (width() - space * 2) / 3, up_down_space);
        QPoint left_down = QPoint(space + (width() - space * 2) / 3, height() - up_down_space);
        QPoint right_up = QPoint(space + ((width() - space * 2) / 3) * 2, up_down_space);
        QPoint right_down = QPoint(space + ((width() - space * 2) / 3) * 2, height() - up_down_space);
        painter.drawLine(left_up, left_down);
        painter.drawLine(right_up, right_down);
    }else{
        int up_down_space = width() / 10;
        QPoint left_up = QPoint(up_down_space, space + (height() - space * 2) / 3);
        QPoint left_down = QPoint(2 * space + (width() - space * 2) - up_down_space, space + (height() - space * 2) / 3);
        QPoint right_up = QPoint(up_down_space, space + ((height() - space * 2) / 3) * 2);
        QPoint right_down = QPoint(2 * space + (width() - space * 2) - up_down_space, space + ((height() - space * 2) / 3) * 2);
        painter.drawLine(left_up, left_down);
        painter.drawLine(right_up, right_down);
    }

    painter.restore();
}

/*
 * 将数字矫正到中心
 */
void RollingBox::homing()
{
    if(m_deviation > width()/8)
    {
        homingAni->setStartValue((width() - 1) / 8 - m_deviation);
        homingAni->setEndValue(0);
        m_currentValue--;
        if (m_currentValue < m_minRange)
            m_currentValue = m_maxRange;
    }
    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++;
        if (m_currentValue > m_maxRange)
            m_currentValue = m_minRange;
    }
    emit currentValueChanged(m_currentValue);
    homingAni->start();
}

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

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

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kk电子粉丝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值