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();
}
相关推荐
A.A呐8 小时前
【QT第三章】常用控件2
开发语言·qt
笨笨马甲8 小时前
Qt 实现三维坐标系的方法
开发语言·qt
谁动了我的代码?9 小时前
VNC中使用QT的GDB调试,触发断点时与界面窗口交互导致整个VNC冻结
开发语言·qt·svn
肖恭伟10 小时前
QtCreator Linux ubuntu24.04问题集合
linux·windows·qt
vegetablesssss11 小时前
QT国际化翻译
qt
困死,根本不会11 小时前
Qt Designer 基础操作学习笔记
开发语言·笔记·qt·学习·microsoft
喜欢喝果茶.12 小时前
Qt MQTT部署
开发语言·qt
浅碎时光80712 小时前
Qt 窗口 (菜单 工具栏 状态栏 浮动窗口 对话框)
qt
GIS阵地12 小时前
一场由Qt5 painter的drawRect引起的血雨腥风
开发语言·qt·gis·qgis
娇娇yyyyyy12 小时前
QT编程(8): qt自定义菜单项
qt·microsoft