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

效果如图:

在这里插入图片描述
布局如图:

在这里插入图片描述
参考代码:

//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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/441517.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

给一篇word注音可不可以只要拼音不要汉字 word中如何只保留拼音不要汉字

word中如何只保留拼音不要汉字&#xff0c;如果你想要只保留拼音而去除汉字&#xff0c;可以通过一系列步骤来实现。以下是一个详细的教程&#xff0c;帮助你完成这个任务。 首先&#xff0c;确保你的电脑已经安装了“汇帮注音大师”软件。如果没有&#xff0c;你需要安装一下…

仿12306校招项目业务五(敏感信息模块)

加密存储 数据加密背景 数据加密是指对某些敏感信息通过加密规则进行数据的变形&#xff0c;实现敏感隐私数据的可靠保护。 涉及客户安全数据或者一些商业性敏感数据&#xff0c;如身份证号、手机号、卡号、客户号等个人信息按照相关部门规定&#xff0c;都需要进行数据加密。…

app逆向-ratel框架-sekiro框架的安装使用

文章目录 一、前言二、初次尝试三、案例测试 一、前言 sekiro主要支持多节点的程序调用&#xff0c;所以他归属于RPC&#xff08;Remote Procedure Call&#xff09;框架&#xff1a;API管理、鉴权、分布式、负载均衡、跨语言 开源文档&#xff1a;https://sekiro.iinti.cn/s…

python使用Open3D 对点云重建与c++使用PCL对点云进行重建哪个效率更高

确定哪个库更高效取决于多个因素&#xff0c;包括算法实现、优化程度、硬件配置等。通常情况下&#xff0c;C 的 PCL 库在性能方面可能会比 Python 的 Open3D 库更高&#xff0c;因为 C 语言的编译器可以生成更高效的机器码&#xff0c;并且 PCL 库的底层实现是经过高度优化的。…

C++:模版进阶 | Priority_queue的模拟实现

创作不易&#xff0c;感谢三连支持 一、非类型模版参数 模板参数分类为类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&…

AIGC启示录:深度解析AIGC技术的现代性与系统性的奇幻旅程

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

LayerNorm的图是不是画错了

这是网上一张很流行的说明几个 Normalization 区别的图 这图出自Kaiming的文章 Group Norm 但是他这个 Layer Norm 的图是不是画错了? 我大四写毕设的时候就想问&#x1f923;&#x1f923;&#x1f923; 这都几年过去了 我觉得图应该是这样画的&#xff0c;相同颜色的区域…

HifiFace: 3D形状和语义先验引导高保真人脸交换阅读笔记

HifiFace: 3D Shape and Semantic Prior Guided High Fidelity Face Swapping HifiFace: 3D形状和语义先验引导高保真人脸交换 介绍 可以很好地保留源人脸的脸型&#xff0c;并产生逼真的结果。不同于现有的人脸交换只使用人脸识别模型来保持身份相似性的方法&#xff0c;我们…

【万题详解】DFS搜索专题合集(上)

专栏推荐 我的专栏——专栏链接 1.文章平均质量分 70分以上 2.以洛谷题为基础&#xff0c;解决C问题 3.有题目、讲解、思路、参考代码…… 4. 文章数&#xff1a;29 &#xff08;2024.3.8&#xff09; 课前C小程序&#xff08;脱控极域电子教室&#xff09; 这个图标相信…

C语言分析基础排序算法——选择排序

目录 选择排序 选择排序 堆排序 选择排序 选择排序 选择排序的基本思路是&#xff0c;定义两个区间指针begin和end&#xff0c;遍历数组中的每一个数据找出最大的数据的下标和最小的数据的下标&#xff0c;之后与begin和end指针分别交换小数据与begin的位置以及大数据和e…

计算机设计大赛 深度学习驾驶行为状态检测系统(疲劳 抽烟 喝水 玩手机) - opencv python

文章目录 1 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的驾…

如何保证消息不丢之MQ重试机制消息队列

1. 简介 死信队列&#xff0c;简称&#xff1a;DLX&#xff0c;Dead Letter Exchange&#xff08;死信交换机&#xff09;&#xff0c;当消息成为Dead message后&#xff0c;可以被重新发送到另外一个交换机&#xff0c;这个交换机就是DLX 那么什么情况下会成为Dead message&a…

全球科技创新领域大检阅“2024上海国际智能科技及创新展览会”

随着科技的飞速发展&#xff0c;创新成为了推动社会进步的核心动力。在这样的背景下&#xff0c;“2024上海国际科技及创新展览会”应运而生&#xff0c;旨在汇聚全球智能科技领域的精英&#xff0c;共同展示最新的科技成果&#xff0c;探讨未来的发展方向。 本次展会将于2024年…

Alveo 概念拓扑结构

在 Alveo 加速卡中,涉及到的概念拓扑结构主要包括 Alveo 卡上的各个关键组件以及与主机系统之间的通信结构。以下是对这些概念拓扑结构的简要介绍: 1.DDR 即双数据率内存(Double Data Rate memory),是一种常见的计算机内存类型,用于存储和提供处理器所需的数据和指令。…

HBase安装,配置,启动,检查

目录: 一、HBase安装&#xff0c;配置 1、下载HBase安装包 2、解压&#xff0c;配置环境变量并激活 3、hbase 配置 4、将hadoop和zookeeper的配置文件创建软连接放在hbase配置目录 5、配置 regionserver 二、HBase启动与关闭&#xff0c;安装检验 1、启动关闭hbase的命令 2、 检…

mac本地启动sentinel

启动Sentinel控制台 1&#xff09;下载sentinel控制台jar包 https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar 2&#xff09;启动sentinel控制台 使用如下命令启动控制台&#xff1a; java -Dserver.port8080 -Dcsp.sentinel.d…

基于单片机的红外测距仪设计

目 录 摘 要 I Abstract II 引 言 1 1 控制系统设计 3 1.1 主控制器选择 3 1.2 项目总体设计 3 2 项目硬件设计 5 2.1 单片机控制模块 5 2.2 测距模块设计 9 2.3 液晶显示模块 10 2.4 报警模块 11 3 项目软件设计 12 3.1 软件开发环境 12 3.2 系统主程序设计 13 3.3 LCD显示程…

数智化时代的新潮流:企业如何利用数据飞轮驱动增长?_光点科技

随着数据中台理念的逐渐“降温”&#xff0c;企业数智化的探索并未停歇。反而&#xff0c;数据飞轮成为了新的焦点&#xff0c;它承诺为企业带来更紧密的业务与数据结合&#xff0c;从而推动持续的增长。本文将探讨企业如何利用数据飞轮的概念&#xff0c;赋能业务&#xff0c;…

Spark 核心API

核心 API spark core API 指的是 spark 预定义好的算子。无论是 spark streaming 或者 Spark SQL 都是基于这些最基础的 API 构建起来的。理解这些核心 API 也是写出高效 Spark 代码的基础。 Transformation 转化类的算子是最多的&#xff0c;学会使用这些算子就应付多数的数…

勒索软件事件手册:综合指南

近年来&#xff0c;勒索软件攻击的频率和复杂程度都急剧增加。这些攻击的影响可能是毁灭性的&#xff0c;从经济损失到严重的运营中断。 这就是为什么对于希望防范这种网络安全威胁的企业来说&#xff0c; 强大的勒索软件事件响应手册是不可谈判的。 本指南旨在深入了解勒索软…