qt自定义时间选择控件窗口

效果如图:

布局如图:

参考代码:

cpp 复制代码
//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
cpp 复制代码
#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));
    }
}
cpp 复制代码
//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
cpp 复制代码
#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();
}
相关推荐
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
「QT(C++)开发工程师」11 小时前
【qt版本概述】
开发语言·qt
一路冰雨14 小时前
Qt打开文件对话框选择文件之后弹出两次
开发语言·qt
老赵的博客15 小时前
QT 自定义界面布局要诀
开发语言·qt
码码哈哈0.015 小时前
VSCode 2022 离线安装插件QT VSTOOl报错此扩展不能安装在任何当前安装的产品上。
ide·vscode·qt
feiyangqingyun19 小时前
Qt/C++离线地图的加载和交互/可以离线使用/百度和天地图离线/支持手机上运行
c++·qt·qt天地图·qt离线地图·qt地图导航
gz94561 天前
windows下,用CMake编译qt项目,出现错误By not providing “FindQt5.cmake“...
开发语言·qt
「QT(C++)开发工程师」1 天前
Ubuntu 26.04 LTS 大升级:Qt 6 成为未来新引擎
qt
兆。1 天前
python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具
爬虫·python·qt
喝哈喝哈2 天前
pycharm中配置pyqt5
python·qt·pycharm