想做个循环滑动选择控件,于是在网上找了相应的代码如下链接:【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();
}