前言
有个需求要实现类似的功能,网上参考了别人代码自己修改了下。
方案一原文链接 Qt编写自定义控件:卷轴式数字滚动 ----作者: 友善啊,朋友
方案二原文链接 QT自定义控件–滑动选择器 ----作者: Qt程序员
提示:以下是本篇文章正文内容,下面案例可供参考
方案一:
效果展示
ReelWidget.h
代码如下(示例):
#ifndef REELWIDGET_H
#define REELWIDGET_H
#include <QWidget>
#include <QTimer>
#include <QPainter>
#include <QPaintEvent>
#include <QQueue>
#include <QDebug>
class ReelWidget : public QWidget
{
Q_OBJECT
public:
ReelWidget(QWidget *parent = nullptr);
void initData();
void setNewNumber(int newNumber);
inline int getCurrentNumberValue(){return currentNumber;}
protected:
void keyPressEvent(QKeyEvent *e)override;
void paintEvent(QPaintEvent *)override;
void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event)override;
void mouseReleaseEvent(QMouseEvent *event)override;
private slots:
void onTimer();
private:
void drawAUnit(const QRect &rect, QPainter * painter, int number);
public slots:
void setValue(int flag);
private:
enum class state
{
noRun,
runing_up,
runing_down
};
int number;
int MAX_NUM;
int MIN_NUM;
int lastNumber;
int currentNumber;
int currentNumberA;
int currentNumberB;
int currentNumberC;
const QPixmap bg;
bool isRuning;
bool isLeftPressDown;
QPoint pressPoint;
QTimer timer;
QRect rectA;
QRect rectB;
QRect rectC;
state widgetState{state::noRun};
QRect whenRuningImageRect_Current;
QRect whenRuningImageRect_Last;
};
#endif // REELWIDGET_H
ReelWidget.cpp
代码如下(示例):
#include "reelwidget.h"
int rateFactor = 5;
ReelWidget::ReelWidget(QWidget *parent)
: QWidget(parent),bg{"://bg.png"}
{
initData();
}
void ReelWidget::initData()
{
number = 0;
MAX_NUM = 10;
MIN_NUM = -10;
lastNumber = 0;
currentNumber = 0;
currentNumberA = 1;
currentNumberB = 0;
currentNumberC = -1;
isRuning = false;
isLeftPressDown = false;
setFocusPolicy(Qt::StrongFocus);
setFixedSize(200,90);
auto font = this->font();
font.setPixelSize(18);
font.setFamily("方正小标宋简体");
setFont(font);
whenRuningImageRect_Last = QRect(this->rect().x(), -this->rect().height()/3, this->rect().width(), this->rect().height()/3);
rectA = QRect(this->rect().x(), 0, this->rect().width(), this->rect().height()/3);
rectB = QRect(this->rect().x(), this->rect().height()/3*1, this->rect().width(), this->rect().height()/3);
rectC = QRect(this->rect().x(), this->rect().height()/3*2, this->rect().width(), this->rect().height()/3);
connect(&timer,&QTimer::timeout,this,&ReelWidget::onTimer);
timer.setInterval(60);
}
void ReelWidget::setNewNumber(int newNumber)
{
if(this->widgetState == state::runing_up){
lastNumber = currentNumberA;
currentNumberA = newNumber;
currentNumberB = currentNumberA-1;
currentNumberC = currentNumberB-1;
currentNumber = currentNumberB;
whenRuningImageRect_Last = QRect(this->rect().x(), 0, this->rect().width(), this->rect().height()/3);
rectA = QRect(this->rect().x(), this->rect().height()/3*1, this->rect().width(), this->rect().height()/3);
rectB = QRect(this->rect().x(), this->rect().height()/3*2, this->rect().width(), this->rect().height()/3);
rectC = QRect(this->rect().x(), this->rect().height(), this->rect().width(), this->rect().height()/3);
timer.start();
}
else if(this->widgetState == state::runing_down){
lastNumber = currentNumberC;
currentNumberC = newNumber;
currentNumberB = currentNumberC+1;
currentNumberA = currentNumberB+1;
currentNumber = currentNumberB;
rectA = QRect(this->rect().x(), -this->rect().height()/3, this->rect().width(), this->rect().height()/3);
rectB = QRect(this->rect().x(), 0, this->rect().width(), this->rect().height()/3);
rectC = QRect(this->rect().x(), this->rect().height()/3*1, this->rect().width(), this->rect().height()/3);
whenRuningImageRect_Last = QRect(this->rect().x(), this->rect().height()/3*2, this->rect().width(), this->rect().height()/3);
timer.start();
}
}
void ReelWidget::wheelEvent(QWheelEvent *event)
{
if(event->delta() >= 120){
if(currentNumber == MAX_NUM-1) return;
widgetState = state::runing_down;
setNewNumber(number);
number++;
}
else{
if(currentNumber == MIN_NUM+1) return;
widgetState = state::runing_up;
setNewNumber(number);
number--;
}
}
void ReelWidget::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_Up:
if(currentNumber == MAX_NUM-1) break;
widgetState = state::runing_down;
setNewNumber(number);
number++;
break;
case Qt::Key_Down:
if(currentNumber == MIN_NUM+1) break;
widgetState = state::runing_up;
setNewNumber(number);
number--;
break;
default:
break;
}
}
void ReelWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setFont(this->font());
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setRenderHint(QPainter::SmoothPixmapTransform,true);
#if 0
QRect rectBackGroundA = QRect(this->rect().x(), 0, this->rect().width(), this->rect().height()/3);
QRect rectBackGroundB = QRect(this->rect().x(), this->rect().height()/3*1, this->rect().width(), this->rect().height()/3);
QRect rectBackGroundC = QRect(this->rect().x(), this->rect().height()/3*2, this->rect().width(), this->rect().height()/3);
#if 0
painter.drawPixmap(rectBackGroundA, bg.scaled(this->rect().size()));
painter.drawPixmap(rectBackGroundC, bg.scaled(this->rect().size()));
QPixmap pix("://bg1.png");
painter.drawPixmap(rectBackGroundB, pix.scaled(this->rect().size()));
#endif
#if 0
QColor colorBackGround = QColor(0, 0, 0);
painter.setBrush(colorBackGround);
painter.drawRect(rectBackGroundA);
painter.drawRect(rectBackGroundC);
colorBackGround = QColor(87, 87, 87);
painter.setBrush(colorBackGround);
painter.drawRect(rectBackGroundB);
#endif
#endif
if(widgetState == state::runing_up)
{
drawAUnit(whenRuningImageRect_Last,&painter,lastNumber);
drawAUnit(rectA,&painter,currentNumberA);
drawAUnit(rectB,&painter,currentNumberB);
drawAUnit(rectC,&painter,currentNumberC);
}
else if(widgetState == state::runing_down)
{
drawAUnit(rectA,&painter,currentNumberA);
drawAUnit(rectB,&painter,currentNumberB);
drawAUnit(rectC,&painter,currentNumberC);
drawAUnit(whenRuningImageRect_Last,&painter,lastNumber);
}
else if(widgetState == state::noRun)
{
drawAUnit(rectA,&painter,currentNumberA);
drawAUnit(rectB,&painter,currentNumberB);
drawAUnit(rectC,&painter,currentNumberC);
}
}
void ReelWidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
isLeftPressDown = true;
pressPoint = event->globalPos();
}
}
void ReelWidget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton && isLeftPressDown){
isLeftPressDown = false;
QPoint movePos = event->globalPos();
int moveY = movePos.y() - pressPoint.y();
if(moveY >= 5){
if(currentNumber == MAX_NUM-1) return;
widgetState = state::runing_down;
setNewNumber(number);
number++;
}
else if(moveY <= -5){
if(currentNumber == MIN_NUM+1) return;
widgetState = state::runing_up;
setNewNumber(number);
number--;
}
}
}
void ReelWidget::onTimer()
{
if(widgetState == state::runing_up){
auto currentTop = rectA.top() - rateFactor;
if(currentTop <= -5){
timer.stop();
widgetState = state::noRun;
qDebug()<< "当前值: " << currentNumber;
}
else{
whenRuningImageRect_Last.moveTop(whenRuningImageRect_Last.top() - rateFactor);
rectA.moveTop(currentTop);
rectB.moveTop(rectB.top() - rateFactor);
rectC.moveTop(rectC.top() - rateFactor);
}
}
else if(widgetState == state::runing_down){
auto currentTop = rectA.top() + rateFactor;
if(currentTop >= 5){
timer.stop();
widgetState = state::noRun;
qDebug()<< "当前值: " << currentNumber;
}
else{
rectA.moveTop(currentTop);
rectB.moveTop(rectB.top() + rateFactor);
rectC.moveTop(rectC.top() + rateFactor);
whenRuningImageRect_Last.moveTop(whenRuningImageRect_Last.top() + rateFactor);
}
}
update();
}
void ReelWidget::setValue(int flag)
{
if(flag == 1){
widgetState = state::runing_down;
setNewNumber(number);
number++;
}
else{
widgetState = state::runing_up;
setNewNumber(number);
number--;
}
}
void ReelWidget::drawAUnit(const QRect & rect, QPainter * painter, int number)
{
#if 1
painter->drawPixmap(rect, bg.scaled(this->rect().size()));
if(number == currentNumber){
QPixmap pix("://bg1.png");
painter->drawPixmap(rect, pix.scaled(this->rect().size()));
}
#endif
#if 0
//绘制背景色
QColor colorBackGround = QColor(0, 0, 0);
painter->setBrush(colorBackGround);
if(number == currentNumber){
colorBackGround = QColor(87, 87, 87);
}
painter->setBrush(colorBackGround);
painter->drawRect(rect);
#endif
painter->setPen(Qt::white);
QString value = QString::number(number);
if(number > 0) value = QString("+%1").arg(number);
if(number == currentNumber){
painter->setPen(QColor(51, 245, 4));
auto font = this->font();
font.setBold(true);
painter->setFont(font);
}
painter->drawText(rect, Qt::AlignCenter, value);
}
方案二:
效果展示
ReelWidget.h
代码如下(示例):
#ifndef SLIDINGSELECTOR_H
#define SLIDINGSELECTOR_H
#include <QWidget>
#include <QDebug>
#include <QTimer>
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>
class SlidingSelector : public QWidget
{
Q_OBJECT
public:
explicit SlidingSelector(QWidget *parent = nullptr);
void initData();
void initConnect();
void paintEvent(QPaintEvent *);
void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event)override;
void mouseMoveEvent(QMouseEvent *event)override;
void mouseReleaseEvent(QMouseEvent *event)override;
void paint_frame(QPainter *painter);
void paint_num(QPainter *painter, int number, int mouse_move_length, int mid);
void paint_parting_line(QPainter *painter);
void keyPressEvent(QKeyEvent *e);
private slots:
void onTimer();
private:
int MAX_NUM;
int MIN_NUM;
int space;
int num_size;
int mouse_Press;
int mouse_move_length;
int Current_num;
bool bUpMove;
QTimer myTimer;
QColor currentNum_color;
QColor besideNum_color;
QColor partingLine_color;
QColor frame_color;
};
#endif // SLIDINGSELECTOR_H
ReelWidget.cpp
代码如下(示例):
#include "slidingselector.h"
SlidingSelector::SlidingSelector(QWidget *parent)
: QWidget(parent)
{
initData();
initConnect();
}
void SlidingSelector::initData()
{
MAX_NUM = 10;
MIN_NUM = -10;
space = 0;
num_size = 9;
mouse_Press;
mouse_move_length = 0;
Current_num = 0;
bUpMove = false;
currentNum_color = QColor(51, 245, 4);
besideNum_color = QColor(255, 255, 255);
partingLine_color = QColor(87, 87, 87);
frame_color = QColor(50, 87, 50);
myTimer.setInterval(60);
setFixedSize(300, 240);
setFocusPolicy(Qt::StrongFocus);
}
void SlidingSelector::initConnect()
{
connect(&myTimer,&QTimer::timeout,this,&SlidingSelector::onTimer);
}
void SlidingSelector::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){
mouse_Press = event->globalPos().y();
}
}
void SlidingSelector::mouseMoveEvent(QMouseEvent *event)
{
mouse_move_length = event->globalPos().y() - mouse_Press;
if(mouse_move_length <= -1 && Current_num == MIN_NUM+1){
mouse_move_length = 0;
return;
}
if(mouse_move_length >= 1 && Current_num == MAX_NUM-1){
mouse_move_length = 0;
return;
}
update();
}
void SlidingSelector::mouseReleaseEvent(QMouseEvent *event)
{
if(mouse_move_length <= -1 && Current_num == MIN_NUM+1){
return;
}
if(mouse_move_length >= 1 && Current_num == MAX_NUM-1){
return;
}
int Height = height();
bool result = false;
if(mouse_move_length >= Height/8 && Current_num < MAX_NUM)
{
result = true;
mouse_move_length = Height/4;
}
else{
if(qAbs(mouse_move_length) >= Height/8 && Current_num > MIN_NUM)
{
result = true;
mouse_move_length = -Height/4;
}
}
if(result == false){
mouse_Press = 0;
mouse_move_length = 0;
}
update();
}
void SlidingSelector::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_Up:
if(Current_num == MIN_NUM+1) break;
bUpMove = true;
myTimer.start();
break;
case Qt::Key_Down:
if(Current_num == MAX_NUM-1) break;
bUpMove = false;
myTimer.start();
break;
default:
break;
}
}
void SlidingSelector::onTimer()
{
int Height = height();
if(bUpMove){
mouse_move_length -= Height/20;
if(mouse_move_length <= -Height/4 && Current_num < MAX_NUM){
myTimer.stop();
}
}
else{
mouse_move_length += Height/20;
if(mouse_move_length >= Height/4 && Current_num > MIN_NUM){
myTimer.stop();
}
}
update();
}
void SlidingSelector::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
paint_frame(&painter);
#if 0
paint_parting_line(&painter);
#endif
int Height = height();
if(mouse_move_length >= Height/4 && Current_num < MAX_NUM)
{
Current_num += 1;
mouse_Press += Height/4;
mouse_move_length -= Height/4;
}
if(mouse_move_length <= -Height/4 && Current_num > MIN_NUM)
{
Current_num -= 1;
mouse_Press -= Height/4;
mouse_move_length += Height/4;
}
//中间数字
paint_num(&painter,Current_num,mouse_move_length,1);
//上下两行数字
if(Current_num != MAX_NUM)
paint_num(&painter,Current_num+1,mouse_move_length-Height/4-20,0);
if(Current_num != MIN_NUM)
paint_num(&painter,Current_num-1,mouse_move_length+Height/4+20,0);
}
void SlidingSelector::wheelEvent(QWheelEvent *event)
{
if(event->delta() >= 120){
if(Current_num == MAX_NUM-1) return;
bUpMove = false;
myTimer.start();
}
else{
if(Current_num == MIN_NUM+1) return;
bUpMove = true;
myTimer.start();
}
}
void SlidingSelector::paint_frame(QPainter *painter)
{
painter->save();
painter->setPen(Qt::NoPen);
#if 0
painter->setBrush(frame_color);
painter->drawRect(space,space,width()-space*2,height()-space*2);
#endif
#if 1
QRect rectAbove = QRect(space, height()/3*0, width(), height()/3);
QRect rectCentre = QRect(space, height()/3*1, width(), height()/3);
QRect rectBelow = QRect(space, height()/3*2, width(), height()/3);
QColor colorBackGround = QColor(0, 0, 0);
painter->setBrush(colorBackGround);
painter->drawRect(rectAbove);
painter->drawRect(rectBelow);
colorBackGround = QColor(87, 87, 87);
painter->setBrush(colorBackGround);
painter->drawRect(rectCentre);
#endif
painter->restore();
}
void SlidingSelector::paint_num(QPainter *painter,int number,int mouse_move_length,int mid)
{
painter->save();
int Width = this->width();
int Height = this->height();
int size = qAbs((Height - qAbs(mouse_move_length))/num_size);//像素尺寸
int height = Height/2-3*qAbs(mouse_move_length);//数字框宽度
int y = Height/2+mouse_move_length-height/2;//数字框x坐标
QFont font;
font.setPixelSize(size);
painter->setFont(font);
if(mid == 1)
painter->setPen(currentNum_color);
else
painter->setPen(besideNum_color);
QString value = QString::number(number);
if(number > 0) value = QString("+%1").arg(number);
painter->drawText(QRectF(0, y, Width, height),Qt::AlignCenter, value);
painter->restore();
}
void SlidingSelector::paint_parting_line(QPainter *painter)
{
painter->save();
QPen pen;
pen.setBrush(partingLine_color);
pen.setWidth(4);
pen.setCapStyle(Qt::RoundCap);
pen.setStyle(Qt::SolidLine);
painter->setPen(pen);
int up_down_space = width()/10;
QPoint line_left_up = QPoint(space+up_down_space,space+(height()-space*2)/3);
QPoint line_left_down = QPoint(space+(width()-space*2)-up_down_space,space+(height()-space*2)/3);
QPoint line_right_up = QPoint(space+up_down_space,space+((height()-space*2)/3)*2);
QPoint line_right_down = QPoint(space+(width()-space*2)-up_down_space,space+((height()-space*2)/3)*2);
painter->drawLine(line_left_up,line_left_down);//绘制左侧分割线
painter->drawLine(line_right_up,line_right_down);//绘制右侧分割线
painter->restore();
}