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

news2024/12/23 22:15:24

效果如图:

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【手游联运平台搭建】游戏平台的作用

随着科技的不断发展&#xff0c;游戏行业也在不断壮大&#xff0c;而游戏平台作为连接玩家与游戏的桥梁&#xff0c;发挥着越来越重要的作用。游戏平台不仅为玩家提供了便捷的游戏体验&#xff0c;还为游戏开发者提供了广阔的市场和推广渠道。本文将从多个方面探讨游戏平台的作…

扩展CArray类,增加Contain函数

CArray不包含查找类的函数&#xff0c;使用不便。考虑扩展CArray类&#xff0c;增加Contain函数&#xff0c;通过回调函数暴露数组元素的比较方法&#xff0c;由外部定义。该方法相对重载数组元素的“”符号更加灵活&#xff0c;可以根据需要配置不同的回调函数进行比较 //类型…

继深圳后,重庆与鸿蒙展开原生应用开发合作

截至2023年底&#xff0c;开源鸿蒙开源社区已有250多家生态伙伴加入&#xff0c;开源鸿蒙项目捐赠人达35家&#xff0c;通过开源鸿蒙兼容性测评的伙伴达173个&#xff0c;累计落地230余款商用设备&#xff0c;涵盖金融、教育、智能家居、交通、数字政府、工业、医疗等各领域。 …

底层day3作业

思维导图 作业&#xff1a;1.总结任务的调度算法&#xff0c;把实现代码再写一下 算法&#xff1a;抢占式调度时间片轮转 1.抢占式调度&#xff1a;任务优先级高的可以打断任务优先级低的执行&#xff08;适用于不同优先级&#xff09; 2.时间片轮转&#xff1a;每一个任务拥…

react的diff源码

react 的 render 阶段&#xff0c;其中 begin 时会调用 reconcileChildren 函数&#xff0c; reconcileChildren 中做的事情就是 react 知名的 diff 过程 diff 算法介绍 react 的每次更新&#xff0c;都会将新的 ReactElement 内容与旧的 fiber 树作对比&#xff0c;比较出它们…

电脑小问题:Windows更新后黑屏

Windows 更新后黑屏解决方法 在 Windows 更新后&#xff0c;伴随了一个小问题&#xff0c;电脑启动后出现了桌面黑屏。原因可能是火绒把 explorer.exe 当病毒处理了。 下面讲解 Windows 更新后黑屏的解决方法&#xff0c;步骤如下&#xff1a; 1. 按 ctrl alt delete 组合键…

基于Python3的数据结构与算法 - 12 数据结构(列表和栈)

目录 一、引入 二、分类 三、列表 1. C语言中数组的存储方式 2. Python中列表的存储方式 四、栈 1. 栈的应用 -- 括号匹配问题 一、引入 定义&#xff1a;数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。简单来说&#x…

portainer管理远程docker和docker-swarm集群

使用前请先安装docker和docker-compose&#xff0c;同时完成docker-swarm集群初始化 一、portainer-ce部署 部署portainer-ce实时管理本机docker&#xff0c;使用docker-compose一键拉起 docker-compose.yml version: 3 services:portainer:container_name: portainer#imag…

Docker上部署LPG(loki+promtail+grafana)踩坑复盘

Docker上部署LPG&#xff08;lokipromtailgrafana&#xff09;踩坑复盘 声明网上配置部署踩坑 声明 参考掘金文章&#xff1a;https://juejin.cn/post/7008424451704356872 版本高的用docker compose命令&#xff0c;版本低的用docker-compose 按照文章描述&#xff0c;主要准备…

UVA378 Intersecting Lines 题解

UVA378 Intersecting Lines 题解 怎么这么多点斜式邪教啊。 解法 在计算几何中&#xff0c;我们应该尽可能地避免使用浮点数的计算&#xff0c;尽可能地使用向量计算。 本篇题解默认读者具有向量基础。 为了方便讲解&#xff0c;我们将输入的四个点分别记作 A , B , C , …

本鲸多方位助力创业者高效对接创新创业机遇

在科技创新的浪潮中&#xff0c;创业者们不断探索着新的商业机会&#xff0c;寻求着创新创业的道路。然而&#xff0c;面对复杂多变的市场环境和激烈的竞争压力&#xff0c;如何高效对接创新创业机遇成为了摆在创业者面前的重要课题。 本鲸依托海南本鲸投资有限公司和重庆本鲸…

关于Vivado的实施过程、SDC和XDC约束支持、Vivado实施子流程、Tcl API支持脚本

关于Vivado的实施过程 AMD Vivado™设计套件可实现以下AMD设备体系结构&#xff1a;AMD Versal™自适应计算加速平台&#xff08;自适应SoC&#xff09;&#xff0c;AMDUltraScale™、AMD UltraScale™和AMD 7系列FPGA。各种设计来源如下支持&#xff0c;包括&#xff1a; •…

WebGPU vs. 像素流

在构建 Bzar 之前&#xff0c;我们讨论过我们的技术栈是基于在云上渲染内容的像素流&#xff0c;还是基于使用设备自身计算能力的本地渲染技术。 由于这种选择会极大地影响项目的成本、可扩展性和用户体验&#xff0c;因此在开始编写一行代码之前&#xff0c;从一开始就采取正确…

typeorm-入门

简述 typeorm是一个数据库orm框架&#xff0c;在nestjs官网中有提到&#xff0c;可以充分发挥利用typescript的特性&#xff0c;当然也支持js其中涉及的概念包括 DataSource 数据源&#xff0c;Connection 连接数据库Entity 实体&#xff0c;实体类映射数据库表Relation 关系…

30个炫酷光效视频转场PR模板剪辑素材下载

视频转场Premiere模板&#xff0c;包含30个炫酷光效视频转场过渡效果PR项目模板下载。 适用软件&#xff1a;Premiere Pro 2023 | 分辨率&#xff1a;3840x2160 (4K) | 无需插件 | 文件大小&#xff1a;56.33MB 来自PR转场&#xff0c;下载地址&#xff1a;https://prmuban.com…

Windows下Node.js安装保姆级教程

一、Node.js 下载 访问Node.js官网&#xff0c;点击下载Node.js 下载完成后即可在下载文件中查看安装包 二、安装 一&#xff09;点击安装包开始安装&#xff0c;进入Weclcome界面点击Next 二&#xff09;勾选同意协议&#xff0c;点击Next 三&#xff09;根据需要选择安装路…

Neo4j安装 Linux:CentOS、openEuler 适配langchain应用RAG+知识图谱开发 适配昇腾910B

目录 Neo4j下载上传至服务器后进行解压运行安装JAVA再次运行在windows端打开网页导入数据 Neo4j下载 进入Neo4j官网下载页面 向下滑动找到 Graph Database Self-Managed 选择 社区版&#xff08;COMMUNITY&#xff09; 选择 Linux / Mac Executable Neo4j 5.17.0 (tar) 单机下…

Linux第72步_使用“新字符设备的一般模板”编写LED驱动

使用“新字符设备的一般模板”编写LED驱动&#xff0c;使用寄存器直接开关灯。 1、创建LED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home/zgq/linux/Linux_Drivers/” 输入“ls回车”&#xff0c;查看“/home/zgq/linux/Linux_Drivers/” 输入“mkdi…

egg如何写单元测试

优秀的代码需要有单元测试进行质量保证&#xff0c;每个测试用例都给应用的稳定性提供了一层保障。 测试目录结构 我们约定 test 目录为存放所有测试脚本的目录&#xff0c;测试所使用到的 fixtures 和相关辅助脚本都应该放在此目录下。 测试文件的目录和我们需要测试的文件目…

unicloud where 使用

where介绍 在uniCloud中&#xff0c;WHERE是一个用于指定查询条件的关键字。它允许用户根据特定的条件来筛选和查询云数据库中的数据。WHERE语句的基本语法格式是WHERE condition&#xff0c;其中condition表示查询条件&#xff0c;可以是一个或多个逻辑表达式组成的条件。 在…