效果如图:
布局如图:
参考代码:
//DateTimeSelectWidget
#ifndef DATETIMESELECTWIDGET_H
#define DATETIMESELECTWIDGET_H#include <QWidget>
#include <QDateTime>namespace Ui {
class DateTimeSelectWidget;
}class DateTimeSelectWidget : public QWidget
{Q_OBJECTpublic:explicit DateTimeSelectWidget(QWidget *parent = nullptr);~DateTimeSelectWidget();protected:void showEvent(QShowEvent *event);private:void init_wid_ui();void init_signal_and_slot();signals:void signal_snd_time_update(QString);private slots:void slot_btn_ok_clicked();void slot_update_cur_time_val(int val);private:Ui::DateTimeSelectWidget *ui;
};#endif
#include "datetimeselectwidget.h"
#include "ui_datetimeselectwidget.h"
#include "rollingtimewidget.h"DateTimeSelectWidget::DateTimeSelectWidget(QWidget *parent) :QWidget(parent),ui(new Ui::DateTimeSelectWidget)
{ui->setupUi(this);init_wid_ui();init_signal_and_slot();
}DateTimeSelectWidget::~DateTimeSelectWidget()
{delete ui;
}void DateTimeSelectWidget::showEvent(QShowEvent *event)
{QPushButton *btn = qobject_cast<QPushButton *>(parent());QString curDateTime = btn->text();QStringList list = curDateTime.split(" ");if(list.size() != 2)return;QString date = list[0];QString time = list[1];QStringList datelist = date.split("-");QStringList timelist = time.split(":");if(datelist.size()!=3 || timelist.size()!=3)return;ui->calendarWidget->setSelectedDate(QDate().fromString(date, "yyyy-MM-dd"));ui->wid_hour_select->setCurrTimeVal(QString(timelist[0]).toInt());ui->wid_minute_select->setCurrTimeVal(QString(timelist[1]).toInt());ui->wid_second_select->setCurrTimeVal(QString(timelist[2]).toInt());QWidget::showEvent(event);
}void DateTimeSelectWidget::init_wid_ui()
{this->setWindowFlags(Qt::FramelessWindowHint | Qt::CustomizeWindowHint);//设置时分秒的范围ui->wid_hour_select->setTimeRange(0,23);ui->wid_minute_select->setTimeRange(0,59);ui->wid_second_select->setTimeRange(0,59);
}void DateTimeSelectWidget::init_signal_and_slot()
{connect(ui->wid_hour_select, SIGNAL(signal_update_cur_time_val(int)), this, SLOT(slot_update_cur_time_val(int)));connect(ui->wid_minute_select, SIGNAL(signal_update_cur_time_val(int)), this, SLOT(slot_update_cur_time_val(int)));connect(ui->wid_second_select, SIGNAL(signal_update_cur_time_val(int)), this, SLOT(slot_update_cur_time_val(int)));connect(ui->btn_ok, SIGNAL(clicked()), this, SLOT(slot_btn_ok_clicked()));
}void DateTimeSelectWidget::slot_btn_ok_clicked()
{QDate curDate = ui->calendarWidget->selectedDate();if(curDate.isValid()){QString curDateTime = curDate.toString("yyyy-MM-dd");emit signal_snd_time_update(curDateTime);this->close();}
}void DateTimeSelectWidget::slot_update_cur_time_val(int val)
{QStringList list = ui->lab_hour_minute_second->text().split(":");if(list.size() != 3)return;RollingTimeWidget *wid = qobject_cast<RollingTimeWidget *>(sender());if(wid == ui->wid_hour_select){ui->lab_hour_minute_second->setText(QString("%1:%2:%3").arg(val).arg(list[1]).arg(list[2]));}else if(wid == ui->wid_minute_select){ui->lab_hour_minute_second->setText(QString("%1:%2:%3").arg(list[0]).arg(val).arg(list[2]));}else if(wid == ui->wid_second_select){ui->lab_hour_minute_second->setText(QString("%1:%2:%3").arg(list[0]).arg(list[1]).arg(val));}
}
//RollingTimeWidget
#ifndef ROLLINGTIMEWIDGET_H
#define ROLLINGTIMEWIDGET_H#include <QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QDateTime>
#include <QDebug>class RollingTimeWidget : public QWidget
{Q_OBJECT/* 将采用动画的对象属性注册到QT中去,否则动画将无法执行 */Q_PROPERTY(int posYShifting READ PosYShifting WRITE setPosYShifting)public:explicit RollingTimeWidget(QWidget *parent = nullptr);~RollingTimeWidget();/*** @brief setTimeRange 重新设置显示小时范围函数方法* @param int hour最小值* @param int hour最大值* @return void 无*/void setTimeRange(int min,int max); //设置重新设置范围/*** @brief PosYShifting 获取偏移量* @return int posYShifting*/int PosYShifting();/*** @brief setPosYShifting 设置偏移量* @param int 偏移量设置值* @return void 无*/void setPosYShifting(int posYShifting);void setCurrTimeVal(int val);protected:/*** @brief mousePressEvent 重写鼠标按压事件,鼠标拖动进行滚动* @param QMouseEvent* 鼠标按压事件* @return void 无*/void mousePressEvent(QMouseEvent *event) override;/*** @brief wheelEvent 重写滚轮事件,滚轮进行滚动* @param QWheelEvent* 滚轮事件* @return void 无*/void wheelEvent(QWheelEvent *event) override;/*** @brief mouseMoveEvent 重写鼠标移动事件,鼠标移动进入滚动判决* @param QMouseEvent* 鼠标移动事件* @return void 无*/void mouseMoveEvent(QMouseEvent *event) override;/*** @brief mouseReleaseEvent 重写鼠标松开事件,鼠标松开进入结果判决* @param QMouseEvent* 鼠标松开事件* @return void 无*/void mouseReleaseEvent(QMouseEvent *event) override;/*** @brief paintEvent 重写绘图事件,对hour进行绘制* @param QPaintEvent* 绘图事件* @return void 无*/void paintEvent(QPaintEvent *paint) override;/*** @brief drawNumber 画出滚动数字函数* @param QPaintEvent* 画笔类导入* @param int 数字值value* @param int 滚动偏移量offset* @return void 无*/void drawNumber(QPainter &painter,int value,int offset);/*** @brief rollAnimation 滚动动画方法* @return void 无*/void rollAnimation();signals:void signal_update_cur_time_val(int val);private:/* 最小取值 */int min_Range = 0;/* 最大取值 */int max_Range = 0;/* 字体显示大小 */int numberSize = 5;/* 鼠标移动时判决器 */bool rollingJudgment = false;/* 记录按压鼠标时Y方向的初始位置 */int currentPosY = 0;/* 取系统的小时时间作为滚动时间选择的初始值 */int currentTime = 0;/* 当下的Y方向上的偏移量 */int posYShifting = 0;/* 声明一个动画对象 */QPropertyAnimation rollingAni;
};#endif // ROLLINGTIMEWIDGET_H
#include "rollingtimewidget.h"RollingTimeWidget::RollingTimeWidget(QWidget *parent):QWidget(parent)
{/* 去边框,同时保留窗口原有的属性 */this->setWindowFlags(Qt::FramelessWindowHint | windowFlags());;/* 设置背景样式 */this->setStyleSheet("background:white;");/* 设置动画目标 */rollingAni.setTargetObject(this);/* 设置动画目标属性 */rollingAni.setPropertyName("posYShifting");/* 设置动画持续时间 */rollingAni.setDuration(500);/* 设置动画曲线样式 */rollingAni.setEasingCurve(QEasingCurve::OutCirc);
}RollingTimeWidget::~RollingTimeWidget()
{}void RollingTimeWidget::setTimeRange(int min, int max)
{min_Range = min;max_Range = max;update();
}int RollingTimeWidget::PosYShifting()
{/* 注册属性取值函数 */return posYShifting;
}void RollingTimeWidget::setPosYShifting(int posYShifting)
{/* 注册属性赋值函数 */this->posYShifting = posYShifting;update();
}void RollingTimeWidget::setCurrTimeVal(int val)
{currentTime = val;rollAnimation();update();
}void RollingTimeWidget::mousePressEvent(QMouseEvent *event)
{rollingAni.stop();/* 开启鼠标拖动滚动判决 */rollingJudgment = true;/* 刷新按下时鼠标位置 */currentPosY = event->pos().y();
}void RollingTimeWidget::wheelEvent(QWheelEvent *event)
{/* 以滚轮delta值正负性作为判决条件进行判决 */if(event->delta()>0){if(currentTime > min_Range){posYShifting = this->height()/4;}}else{if(currentTime < max_Range){posYShifting = - this->height()/4;}}rollAnimation();update();
}void RollingTimeWidget::mouseMoveEvent(QMouseEvent *event)
{if(rollingJudgment){if((currentTime == min_Range && event->pos().y() >= currentPosY) || (currentTime == max_Range && event->pos().y() <= currentPosY)){return;}else{posYShifting = event->pos().y() - currentPosY;}update();}
}void RollingTimeWidget::mouseReleaseEvent(QMouseEvent *event)
{Q_UNUSED(event);/*拖动判决归位*/if(rollingJudgment){rollingJudgment = false;/* 开启动画 */rollAnimation();}
}void RollingTimeWidget::paintEvent(QPaintEvent *paint)
{Q_UNUSED(paint);/* 创建画笔对象 */QPainter painter(this);/* 画笔抗锯齿操作 */painter.setRenderHint(QPainter::TextAntialiasing);painter.setRenderHint(QPainter::Antialiasing, true);/* 偏移量检测,以1/4高度和取值范围为边界 */if(posYShifting >= height() / 4 && currentTime > min_Range){/* 鼠标起始位置归位,即加上1/4的高度 */currentPosY += height()/4;/* 偏移量归位,即减去1/4的高度 */posYShifting -= height()/4;/* currentTime自减 */currentTime -= 1;}if(posYShifting <= -height() / 4 && currentTime < max_Range){currentPosY -= height() / 4;posYShifting += height() / 4;currentTime += 1;}/* 调用函数画出数字currentTime */drawNumber(painter,currentTime,posYShifting);/* 调用函数画出两侧数字 */if(currentTime != min_Range){drawNumber(painter,currentTime - 1,posYShifting - height() / 4);}if(currentTime != max_Range){drawNumber(painter,currentTime + 1,posYShifting + height() / 4);}/* 调用函数画出两侧数字 */if(posYShifting >= 0 && currentTime - 2 >= min_Range){drawNumber(painter,currentTime - 2,posYShifting - height() / 2);}if(posYShifting <= 0 && currentTime + 2 <= max_Range){drawNumber(painter,currentTime + 2,posYShifting + height() / 2);}/* 画出数字currentTime两侧边框 */painter.setPen(QPen(QColor(70,144,249),2));painter.drawLine(0,height() / 8 * 3,width(),height() / 8 * 3);painter.drawLine(0,height() / 8 * 5,width(),height() / 8 * 5);emit signal_update_cur_time_val(currentTime);
}void RollingTimeWidget::drawNumber(QPainter &painter, int value, int offset)
{/* 通过偏移量控制数字大小size */int size = (this->height() - abs(offset)) / numberSize;/* 通过偏移量控制数字透明度transparency */int transparency = 255 - 510 * abs(offset) / height();/* 通过偏移量控制数字在ui界面占据空间高度height */int height = this->height() / 2 - 3 * abs(offset) / 5;/* 计算数字显示位置 */int y = this->height() / 2 + offset - height / 2;QFont font;/* 设置字体大小 */font.setPixelSize(size);/* 画笔设置字体 */painter.setFont(font);/* 画笔设置颜色 */painter.setPen(QColor(0,0,0,transparency));/* 画笔painter画出文本*/painter.drawText(QRectF(0,y,width(),height),Qt::AlignCenter,(QString::number(value)));
}void RollingTimeWidget::rollAnimation()
{/* 动画判决,达到条件开启相应动画 */if(posYShifting > height() / 8){/* 设置属性动画初始value */rollingAni.setStartValue(height() / 8 - posYShifting);/* 设置属性动画终止value */rollingAni.setEndValue(0);/* currentTime值变更 */currentTime--;}else if(posYShifting > -height() / 8){/* 设置属性动画初始value */rollingAni.setStartValue(posYShifting);/* 设置属性动画终止value */rollingAni.setEndValue(0);}else if(posYShifting < -height() / 8){/* 设置属性动画初始value */rollingAni.setStartValue(-height() / 8 - posYShifting);/* 设置属性动画终止value */rollingAni.setEndValue(0);/* currentTime值变更 */currentTime++;}/* 动画开始 */rollingAni.start();update();
}