效果如图:
布局如图:
参考代码:
//DateTimeSelectWidget
#ifndef DATETIMESELECTWIDGET_H
#define DATETIMESELECTWIDGET_H
#include <QWidget>
#include <QDateTime>
namespace Ui {
class DateTimeSelectWidget;
}
class DateTimeSelectWidget : public QWidget
{
Q_OBJECT
public:
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();
}