Ver código fonte

V0.10
1、新添加了时间选择器,但是还有问题

Apple 3 semanas atrás
pai
commit
0e35bf39dd
29 arquivos alterados com 2105 adições e 3 exclusões
  1. 4 2
      CMakeLists.txt
  2. 1 1
      External
  3. 85 0
      demo/Component/SelectTime/CMakeLists.txt
  4. 54 0
      demo/Component/SelectTime/SelectTime/Res/dark/timepartwidget.qss
  5. 20 0
      demo/Component/SelectTime/SelectTime/Res/dark/timewidget.qss
  6. BIN
      demo/Component/SelectTime/SelectTime/Res/image/time.png
  7. BIN
      demo/Component/SelectTime/SelectTime/Res/image/timing_black.png
  8. BIN
      demo/Component/SelectTime/SelectTime/Res/image/timing_blue.png
  9. 55 0
      demo/Component/SelectTime/SelectTime/Res/light/timepartwidget.qss
  10. 98 0
      demo/Component/SelectTime/SelectTime/Res/light/timepopupwidget.qss
  11. 40 0
      demo/Component/SelectTime/SelectTime/Res/light/timewidget.qss
  12. 10 0
      demo/Component/SelectTime/SelectTime/SelectTime.qrc
  13. 25 0
      demo/Component/SelectTime/SelectTime/mytimedelegate.cpp
  14. 16 0
      demo/Component/SelectTime/SelectTime/mytimedelegate.h
  15. 40 0
      demo/Component/SelectTime/SelectTime/shadowwidget.cpp
  16. 20 0
      demo/Component/SelectTime/SelectTime/shadowwidget.h
  17. 236 0
      demo/Component/SelectTime/SelectTime/timepartwidget.cpp
  18. 54 0
      demo/Component/SelectTime/SelectTime/timepartwidget.h
  19. 61 0
      demo/Component/SelectTime/SelectTime/timepartwidget.ui
  20. 177 0
      demo/Component/SelectTime/SelectTime/timepopupwidget.cpp
  21. 55 0
      demo/Component/SelectTime/SelectTime/timepopupwidget.h
  22. 152 0
      demo/Component/SelectTime/SelectTime/timepopupwidget.ui
  23. 591 0
      demo/Component/SelectTime/SelectTime/timewidget.cpp
  24. 125 0
      demo/Component/SelectTime/SelectTime/timewidget.h
  25. 81 0
      demo/Component/SelectTime/SelectTime/timewidget.ui
  26. 15 0
      demo/Component/SelectTime/main.cpp
  27. 27 0
      demo/Component/SelectTime/widget.cpp
  28. 27 0
      demo/Component/SelectTime/widget.h
  29. 36 0
      demo/Component/SelectTime/widget.ui

+ 4 - 2
CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.12)
 
 project(Library_Project VERSION 1.1 LANGUAGES CXX)
 
@@ -194,7 +194,7 @@ file(GLOB GLOBAL_SRC
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/time)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayer)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/xlsx)
-add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
+# add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ViewModel)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayerGL)
 
@@ -204,3 +204,5 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
 
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/RecordAudio)
 
+add_subdirectory(${CMAKE_SOURCE_DIR}/demo/Component/SelectTime)
+

+ 1 - 1
External

@@ -1 +1 @@
-Subproject commit cf2ebe34adf710c0f9dc18ac82051c6a0b4a6f3f
+Subproject commit 2411453376102eb34dbbbc988b42d627089eab1e

+ 85 - 0
demo/Component/SelectTime/CMakeLists.txt

@@ -0,0 +1,85 @@
+cmake_minimum_required(VERSION 3.12)
+
+#设置C++版本
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(this_exe SelectTime)
+
+
+#包含源文件
+file(GLOB LOCAL_SRC
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.rc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
+
+    ${CMAKE_SOURCE_DIR}/External/common/UIStyle/*.cpp
+    ${CMAKE_SOURCE_DIR}/External/module/Logs/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/SelectTime/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/SelectTime/*.qrc
+)
+
+
+
+# 生成可执行程序
+
+add_executable(${this_exe}
+    # WIN32
+    ${GLOBAL_SRC}
+    ${LOCAL_SRC} 
+)
+
+
+#添加头文件
+target_include_directories(${this_exe} PRIVATE
+
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_SOURCE_DIR}/External/common
+    ${CMAKE_SOURCE_DIR}/External/common/UIStyle
+    ${CMAKE_SOURCE_DIR}/External/module
+    ${CMAKE_SOURCE_DIR}/External/module/Logs
+    ${CMAKE_CURRENT_SOURCE_DIR}/SelectTime  
+    # ${spdlog_INCLUDE_DIR}
+    # ${CURL_INCLUDE_DIR}
+)
+
+target_link_libraries(${this_exe} PRIVATE
+    Qt5::Widgets
+    Qt5::Core
+    Qt5::Network
+    # Qt5::Multimedia
+    # Qt5::Xml
+    # Qt5::Sql
+)
+
+target_link_libraries(${this_exe} PRIVATE 
+    # ${CURL_LIBRARY}
+    # ${spdlog_LIBRARY}
+    External::spdlog
+)
+
+if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)
+    target_link_libraries(${this_exe} PRIVATE
+        stdc++fs
+    )
+endif()
+
+# target_link_libraries(${this_exe} PRIVATE
+#     ${CURL_LIBRARY}
+    
+# )
+# message(STATUS "CURL_LIBRARY: ${CURL_LIBRARY}")
+
+
+# if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug spdlogd.lib
+#         # optimized spdlog.lib
+#     )
+# elseif(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug 
+#         # optimized ${SM_DLL}
+#     )
+# endif()

+ 54 - 0
demo/Component/SelectTime/SelectTime/Res/dark/timepartwidget.qss

@@ -0,0 +1,54 @@
+
+
+QWidget
+{
+    border-radius: 0px;
+    background: #373639;
+}
+
+QListWidget
+{
+    font-size: 14px;
+    color: rgba(255,255,255,0.9);
+	border: none;
+	border-right: 1px solid rgba(0, 0, 0, 0.06);
+	background: #747578;
+	outline: 0px;
+}
+QListView::item:hover 
+{
+    background-color: rgb(227, 238, 255);
+    color: "#3A3F63";
+}
+
+QListView::item:selected 
+{
+    background-color: #438EFF;
+    color: rgba(255,255,255,0.9);
+	outline: none;
+}
+
+QScrollBar:vertical
+{
+	border:none;
+    background-color: #e2e2e2;
+    width: 4px;
+}
+
+QScrollBar::handle:vertical
+{
+	background: #e2e2e2;
+    border-radius: 2px;
+}
+
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}

+ 20 - 0
demo/Component/SelectTime/SelectTime/Res/dark/timewidget.qss

@@ -0,0 +1,20 @@
+QPushButton
+{
+	border-image: url(:/images/datetime.png);
+}
+QPushButton[selected=true]
+{
+	border-image: url(:/images/datetime.png);
+}
+QPushButton::hover[selected=true]
+{
+	border-image: url(:/images/cancle.png);
+}
+
+QDateTimeEdit
+{
+	padding-left: 0px;
+	border: 0px solid #D8D8D8;
+}
+
+

BIN
demo/Component/SelectTime/SelectTime/Res/image/time.png


BIN
demo/Component/SelectTime/SelectTime/Res/image/timing_black.png


BIN
demo/Component/SelectTime/SelectTime/Res/image/timing_blue.png


+ 55 - 0
demo/Component/SelectTime/SelectTime/Res/light/timepartwidget.qss

@@ -0,0 +1,55 @@
+
+QWidget
+{
+    border-radius: 0px;
+    background: #FFFFFF;
+}
+
+
+
+QListWidget
+{
+    font-size: 14px;
+    color: "#3A3F63";
+	border: none;
+	border-right: 1px solid rgba(0, 0, 0, 0.06);
+	background: #ffffff;
+	outline: 0px;
+}
+QListView::item:hover 
+{
+	background-color: rgb(245,245,245);
+    color: "#3A3F63";
+}
+
+QListView::item:selected 
+{
+	background-color: rgb(227, 238, 255);
+    color: "#3A3F63";
+	outline: none;
+}
+
+QScrollBar:vertical
+{
+	border:none;
+    background-color: "#e2e2e2";
+    width: 4px;
+}
+
+QScrollBar::handle:vertical
+{
+	background: #e2e2e2;
+    border-radius: 2px;
+}
+
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}

+ 98 - 0
demo/Component/SelectTime/SelectTime/Res/light/timepopupwidget.qss

@@ -0,0 +1,98 @@
+
+/* ==========================================================
+ *  QPushButton
+ * ========================================================== */
+
+QPushButton
+{
+	font-weight: 500;
+	font-size: 14px;
+	text-align: center;
+}
+
+
+/********* 普通椭圆按钮三种状态效果 *********/
+QPushButton#pBtn_Cancel
+{
+    background: transparent;
+    color: #3A3F63;
+	border: 1px solid #E6E9F4;
+	border-radius: 4px;
+}
+QPushButton#pBtn_Cancel:hover
+{
+    background: transparent;
+	color: #4458FE;
+	border: 1px solid #4458FE;
+    border-radius: 4px;
+}
+
+
+/********* 带有底色椭圆按钮三种状态效果 *********/
+QPushButton#pBtn_Ok
+{
+    color:white;
+    background: qlineargradient( x0:1,x1:1,y1:0,y2:0,stop:1 #4F8AFF,stop:0 #4B5EFF);
+    border-radius: 4px;
+}
+
+QPushButton#pBtn_Ok:hover
+{
+    color:white;
+    background: qlineargradient( x0:1,x1:1,y1:0,y2:0,stop:0 #5D73FF,stop:1 #6092FF);
+    border-radius: 4px;
+}
+
+
+
+/* ==========================================================
+ *  TimePartWidget - QListWidget
+ * ========================================================== */
+
+QListWidget
+{
+    font-size: 14px;
+    color: "#3A3F63";
+	border: none;
+	border-right: 1px solid rgba(0, 0, 0, 0.06);
+	background: #ffffff;
+	outline: 0px;
+}
+QListView::item:hover 
+{
+	background-color: rgb(245,245,245);
+    color: "#3A3F63";
+}
+
+QListView::item:selected 
+{
+	background-color: rgb(227, 238, 255);
+    color: "#3A3F63";
+	outline: none;
+}
+
+QScrollBar:vertical
+{
+	border:none;
+    background-color: "#e2e2e2";
+    width: 4px;
+}
+
+QScrollBar::handle:vertical
+{
+	background: #e2e2e2;
+    border-radius: 2px;
+}
+
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+	background: #ffffff;/*transparent;*/
+    border: none;
+}
+

+ 40 - 0
demo/Component/SelectTime/SelectTime/Res/light/timewidget.qss

@@ -0,0 +1,40 @@
+QPushButton
+{
+	border-image: url(:/Res/image/time.png);
+}
+
+QPushButton[selected=true]
+{
+	border-image: url(:/Res/image/time.png);
+}
+
+QPushButton::hover[selected=true]
+{
+	border-image: url(:/Res/image/time.png);
+}
+
+QDateTimeEdit
+{
+	padding-left: 0px;
+	border: 0px solid #D8D8D8;
+}
+
+/* ==========================================================
+ *  TimeWidget
+ * ========================================================== */
+
+TimeWidget
+{
+	background: #FFFFFF;
+	border-radius: 4px;
+	border: 1px solid #E6E9F4;
+	padding-left: 12px;
+	font-weight: 400;
+	font-size: 14px;
+	color: #3A3F63;
+}
+
+TimeWidget:hover
+{
+	border: 1px solid #4458FE;
+}

+ 10 - 0
demo/Component/SelectTime/SelectTime/SelectTime.qrc

@@ -0,0 +1,10 @@
+<RCC>
+    <qresource prefix="/">
+    <file>Res/image/time.png</file>
+    <file>Res/light/timepartwidget.qss</file>
+    <file>Res/light/timewidget.qss</file>
+    <file>Res/light/timepopupwidget.qss</file>
+    <file>Res/dark/timepartwidget.qss</file>
+    <file>Res/dark/timewidget.qss</file>
+    </qresource>
+</RCC>

+ 25 - 0
demo/Component/SelectTime/SelectTime/mytimedelegate.cpp

@@ -0,0 +1,25 @@
+#include "mytimedelegate.h"
+#include <QPainter>
+#include <QMouseEvent>
+
+MyTimeDelegate::MyTimeDelegate(QObject* parent) :
+    QStyledItemDelegate(parent)
+{
+
+}
+
+void MyTimeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    if (nullptr == painter || !index.isValid()) {
+        return;
+    }
+    QString data = index.data().toString();
+    if (data.isEmpty()) {
+        if ((option.state & QStyle::State_MouseOver) ||
+                (option.state & QStyle::State_Selected)) {
+            painter->fillRect(option.rect, c_bkColor);
+            return;
+        }
+    }
+    QStyledItemDelegate::paint(painter, option, index);
+}

+ 16 - 0
demo/Component/SelectTime/SelectTime/mytimedelegate.h

@@ -0,0 +1,16 @@
+#ifndef MYTIMEDELEGATE_H
+#define MYTIMEDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class MyTimeDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+public:
+    const QColor c_bkColor = QColor(255,255,255);
+    explicit MyTimeDelegate(QObject *parent = nullptr);
+protected:
+     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+};
+
+#endif // MYTIMEDELEGATE_H

+ 40 - 0
demo/Component/SelectTime/SelectTime/shadowwidget.cpp

@@ -0,0 +1,40 @@
+#include "shadowwidget.h"
+#include <QLayout>
+#include <QGraphicsDropShadowEffect>
+#include <QDebug>
+
+ShadowWidget::ShadowWidget(QWidget *parent)
+    : QWidget(parent)
+    , m_pCentralWidget(new QWidget(this))
+{
+    setWindowFlags(Qt::FramelessWindowHint);
+    setAttribute(Qt::WA_TranslucentBackground);
+
+    QHBoxLayout* pLayout = new QHBoxLayout();
+    if (nullptr != pLayout) {
+        pLayout->addWidget(m_pCentralWidget);
+        this->setLayout(pLayout);
+    }
+
+    QGraphicsDropShadowEffect *pShadowEffect = new QGraphicsDropShadowEffect(this);
+    pShadowEffect->setBlurRadius(16);               // 模糊度
+    pShadowEffect->setColor(QColor(0, 0, 0, 90));   // 阴影的颜色
+    pShadowEffect->setOffset(0, 0);                 // 水平和垂直偏移量
+    m_pCentralWidget->setGraphicsEffect(pShadowEffect);
+}
+
+
+void ShadowWidget::setCentralLayout(QLayout *layout)
+{
+    if (nullptr != m_pCentralWidget) {
+        m_pCentralWidget->setLayout(layout);
+    }
+}
+
+QLayout* ShadowWidget::getLayout() const
+{
+    if (nullptr != m_pCentralWidget) {
+        return m_pCentralWidget->layout();
+    }
+    return nullptr;
+}

+ 20 - 0
demo/Component/SelectTime/SelectTime/shadowwidget.h

@@ -0,0 +1,20 @@
+#ifndef SHADOWWIDGET_H
+#define SHADOWWIDGET_H
+
+#include <QWidget>
+
+class ShadowWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit ShadowWidget(QWidget *parent = nullptr);
+
+    QWidget* centralWidget() {return m_pCentralWidget;}
+    void setCentralLayout(QLayout* layout);
+    QLayout* getLayout() const;
+signals:
+private:
+    QWidget* m_pCentralWidget{nullptr};
+};
+
+#endif // SHADOWWIDGET_H

+ 236 - 0
demo/Component/SelectTime/SelectTime/timepartwidget.cpp

@@ -0,0 +1,236 @@
+#include "timepartwidget.h"
+#include "ui_timepartwidget.h"
+#include <QListWidgetItem>
+#include <QScrollBar>
+#include <QDateTime>
+#include <QMouseEvent>
+#include <QDebug>
+#include <QFile>
+#include "mytimedelegate.h"
+// #include "lhstylemanager.h"
+// #include "LHQLogApi.h"
+// #include "UIStyleManager.h"
+#include "spdlog/spdlog.h"
+
+TimePartWidget::TimePartWidget(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::TimePartWidget)
+{
+    ui->setupUi(this);
+}
+
+// TimePartWidget::TimePartWidget(TimePartWidget::emSection type, QWidget* parent) :
+//     TimePartWidget(parent)
+// {
+//     m_type = type;
+//     // 设置代理
+//     m_delegate.reset(new MyTimeDelegate(this));
+//     if (nullptr != m_delegate.data()) {
+//         ui->listWidget->setItemDelegate(m_delegate.data());
+//     }
+
+//     // 设置滚动条
+//     m_pListBar.reset(new QScrollBar(Qt::Orientation::Vertical, ui->listWidget));
+//     if (nullptr != m_pListBar.data()) 
+//     {
+//         m_pListBar->move(width() - 4, 1); // 宽度4,与右侧距离2
+//         m_pListBar->setMinimumHeight(this->height() - 2);
+//         m_pListBar->setMaximumHeight(this->height() - 2);
+//         m_pListBar->hide();
+//         connect(ui->listWidget->verticalScrollBar(), &QScrollBar::valueChanged, m_pListBar.data(), &QScrollBar::setValue);
+//         connect(ui->listWidget->verticalScrollBar(), &QScrollBar::rangeChanged, m_pListBar.data(), &QScrollBar::setRange);
+//         connect(m_pListBar.data(), &QScrollBar::valueChanged, ui->listWidget->verticalScrollBar(), &QScrollBar::setValue);
+//     }
+//     /* 设置QSS */
+//     setQSS();
+
+//     switch (type) {
+//     case MINUTE:
+//     case SECOND: {
+//         InitListWidget(60);
+//         break;
+//     }
+//     case HOUR: {
+//         InitListWidget(24);
+//         break;
+//     }
+//     default:
+//         break;
+//     }
+//     ui->listWidget->setCurrentRow(0);
+//     ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+//     auto pf = [this](QListWidgetItem* item){
+//         ui->listWidget->scrollToItem(item, QAbstractItemView::PositionAtTop); // 滚到最顶部
+//     };
+//     connect(ui->listWidget, &QListWidget::itemPressed, this, pf);
+//     connect(ui->listWidget, &QListWidget::itemPressed, this, &TimePartWidget::sigItemClicked);
+
+// }
+
+TimePartWidget::~TimePartWidget()
+{
+    delete ui;
+}
+
+
+/* 初始化 */
+void TimePartWidget::Init(emSection type)
+{
+    m_type = type;
+    // 设置代理
+    m_delegate.reset(new MyTimeDelegate(this));
+    if (nullptr != m_delegate.data()) {
+        ui->listWidget->setItemDelegate(m_delegate.data());
+    }
+
+    // 设置滚动条
+    m_pListBar.reset(new QScrollBar(Qt::Orientation::Vertical, ui->listWidget));
+    if (nullptr != m_pListBar.data()) 
+    {
+        m_pListBar->move(width() - 4, 1); // 宽度4,与右侧距离2
+        m_pListBar->setMinimumHeight(this->height() - 2);
+        m_pListBar->setMaximumHeight(this->height() - 2);
+        m_pListBar->hide();
+        connect(ui->listWidget->verticalScrollBar(), &QScrollBar::valueChanged, m_pListBar.data(), &QScrollBar::setValue);
+        connect(ui->listWidget->verticalScrollBar(), &QScrollBar::rangeChanged, m_pListBar.data(), &QScrollBar::setRange);
+        connect(m_pListBar.data(), &QScrollBar::valueChanged, ui->listWidget->verticalScrollBar(), &QScrollBar::setValue);
+    }
+    /* 设置QSS */
+    // setQSS();
+
+    switch (type) {
+    case MINUTE:
+    case SECOND: {
+        InitListWidget(60);
+        break;
+    }
+    case HOUR: {
+        InitListWidget(24);
+        break;
+    }
+    default:
+        break;
+    }
+    ui->listWidget->setCurrentRow(0);
+    ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    auto pf = [this](QListWidgetItem* item){
+        ui->listWidget->scrollToItem(item, QAbstractItemView::PositionAtTop); // 滚到最顶部
+    };
+    connect(ui->listWidget, &QListWidget::itemPressed, this, pf);
+    connect(ui->listWidget, &QListWidget::itemPressed, this, &TimePartWidget::sigItemClicked);
+}
+
+
+void TimePartWidget::SetTime(const QDateTime &dt)
+{
+    switch (m_type) {
+    case HOUR:
+        SelectListItem(dt.time().hour());
+        break;
+    case MINUTE:
+        SelectListItem(dt.time().minute());
+        break;
+    case SECOND:
+        SelectListItem(dt.time().second());
+        break;
+    default:
+        break;
+    }
+}
+
+void TimePartWidget::SetMaxWidth(int w)
+{
+    // 更新滚动条位置
+    if (!m_pListBar.isNull()) {
+        m_pListBar->move(w - 4, 1);
+    }
+}
+
+void TimePartWidget::ScrollToSelect()
+{
+    auto items = ui->listWidget->selectedItems();
+    if (items.count() > 0) {
+        ui->listWidget->scrollToItem(items.at(0), QAbstractItemView::PositionAtTop);
+    }
+}
+
+/* 设置QSS */
+// void TimePartWidget::setQSS()
+// {
+//     QString qssPath;
+//     if(UIStyle.getUIStyle() == EUIStyle::UI_Light)
+//     {
+//         qssPath = QString(":/Res/light/timepartwidget.qss");
+//     }
+//     else if(UIStyle.getUIStyle() == EUIStyle::UI_Dark)
+//     {
+//         qssPath = QString(":/Res/dark/timepartwidget.qss");
+//     }
+
+//     QFile file(qssPath);
+//     if(file.open(QFile::ReadOnly))
+//     {
+//         QString styleSheet = QLatin1String(file.readAll());
+//         setStyleSheet(styleSheet);
+//         file.close();
+//     }
+//     else 
+//     {
+//         SPDLOG_ERROR("open qss file failed: {}", qssPath.toStdString());
+//     }
+// }
+
+void TimePartWidget::enterEvent(QEvent *event)
+{
+    if (!m_pListBar.isNull()) {
+        m_pListBar->show();
+    }
+
+    QWidget::enterEvent(event);
+}
+
+void TimePartWidget::leaveEvent(QEvent *event)
+{
+    if (!m_pListBar.isNull()) {
+        m_pListBar->hide();
+    }
+    QWidget::leaveEvent(event);
+}
+
+void TimePartWidget::InitListWidget(int total)
+{
+    ui->listWidget->clear();
+    for (int i = 0; i < total; ++i) {
+        QListWidgetItem* pItem = new QListWidgetItem;
+        if (nullptr == pItem) {
+            continue;
+        }
+        pItem->setTextAlignment(Qt::AlignCenter);
+        pItem->setText(QString("%1").arg(i, 2, 10, QLatin1Char('0')));
+        pItem->setSizeHint(QSize(32, 32));
+        ui->listWidget->addItem(pItem);
+    }
+    // 填充4个不可选空白项
+    for (int i = 0; i < 4; ++i) {
+        QListWidgetItem* pItem = new QListWidgetItem;
+        if (nullptr == pItem) continue;
+        pItem->setSizeHint(QSize(32, 32));
+        pItem->setFlags(pItem->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable);
+        ui->listWidget->addItem(pItem);
+    }
+}
+
+void TimePartWidget::SelectListItem(int time)
+{
+    for (int i = 0; i < ui->listWidget->count(); ++i) {
+        QListWidgetItem* pItem = ui->listWidget->item(i);
+        if (nullptr == pItem) continue;
+        // 注意时间填充了0
+        if (pItem->text() == QString("%1").arg(time, 2, 10, QLatin1Char('0'))) {
+            //qInfo() << "SelectListItem: " << "滚动到最顶部, time: " << time;
+            pItem->setSelected(true);
+            ui->listWidget->scrollToItem(pItem, QAbstractItemView::PositionAtTop); // 滚到最顶部
+            break;
+        }
+    }
+}

+ 54 - 0
demo/Component/SelectTime/SelectTime/timepartwidget.h

@@ -0,0 +1,54 @@
+#ifndef TIMEPARTWIDGET_H
+#define TIMEPARTWIDGET_H
+
+#include <QWidget>
+
+class MyTimeDelegate;
+class QListWidgetItem;
+class QScrollBar;
+
+namespace Ui {
+class TimePartWidget;
+}
+
+class TimePartWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    enum emSection {
+        HOUR = 0,
+        MINUTE = 1,
+        SECOND = 2,
+        MAX_SECTION
+    };
+public:
+    explicit TimePartWidget(QWidget *parent = nullptr);
+    // TimePartWidget(emSection type = emSection::SECOND, QWidget* parent = nullptr);
+    ~TimePartWidget();
+
+    /* 初始化 */
+    void Init(emSection type);
+    emSection GetType() const {return m_type;}
+    void SetTime(const QDateTime& dt);
+    void SetMaxWidth(int w);
+    void ScrollToSelect();
+
+    /* 设置QSS */
+    // void setQSS();
+
+protected:
+    void enterEvent(QEvent* event) override;
+    void leaveEvent(QEvent* event) override;
+signals:
+    void sigItemClicked(QListWidgetItem* item);
+private:
+    void InitListWidget(int total);
+    void SelectListItem(int time);
+private:
+    Ui::TimePartWidget *ui;
+    emSection m_type;
+    QScopedPointer<MyTimeDelegate> m_delegate;
+    QScopedPointer<QScrollBar> m_pListBar;
+};
+
+#endif // TIMEPARTWIDGET_H

+ 61 - 0
demo/Component/SelectTime/SelectTime/timepartwidget.ui

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TimePartWidget</class>
+ <widget class="QWidget" name="TimePartWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>116</width>
+    <height>192</height>
+   </rect>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QListWidget" name="listWidget">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>16777215</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 177 - 0
demo/Component/SelectTime/SelectTime/timepopupwidget.cpp

@@ -0,0 +1,177 @@
+#include "timepopupwidget.h"
+#include "ui_timepopupwidget.h"
+
+#include <QListWidgetItem>
+#include <QFile>
+#include <qobjectdefs.h>
+#include "UIStyleManager.h"
+#include "spdlog/spdlog.h"
+
+
+TimePopupWidget::TimePopupWidget(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::TimePopupWidget)
+{
+    ui->setupUi(this);
+
+    ui->widget_Hour->Init(TimePartWidget::HOUR);
+    ui->widget_Minute->Init(TimePartWidget::MINUTE);
+    ui->widget_Second->Init(TimePartWidget::SECOND);
+
+    connect(ui->widget_Hour, &TimePartWidget::sigItemClicked, this, &TimePopupWidget::do_listItemClicked);
+    connect(ui->widget_Minute, &TimePartWidget::sigItemClicked, this, &TimePopupWidget::do_listItemClicked);
+    connect(ui->widget_Second, &TimePartWidget::sigItemClicked, this, &TimePopupWidget::do_listItemClicked);
+
+    connect(ui->pBtn_Ok, &QPushButton::clicked, this, &TimePopupWidget::do_pBtn_Ok_Clicked);
+    connect(ui->pBtn_Cancel, &QPushButton::clicked, this, &TimePopupWidget::do_pBtn_Cancel_Clicked);
+
+    Reset();
+}
+
+TimePopupWidget::~TimePopupWidget()
+{
+    delete ui;
+}
+
+
+/* 初始化 */
+void TimePopupWidget::Init(const QVector<int> &types)
+{
+    Reset();
+    /* 先隐藏全部的时间条 */
+    ui->widget_Hour->hide();
+    ui->widget_Minute->hide();
+    ui->widget_Second->hide();
+    /* 初始化时间条 */
+    for(const auto& type : types)
+    {
+        TimePartWidget::emSection emType = static_cast<TimePartWidget::emSection>(type);
+        if (emType >= TimePartWidget::emSection::MAX_SECTION) {
+            continue;
+        }
+        if(type == TimePartWidget::HOUR)
+        {
+            ui->widget_Hour->show();
+        }
+        else if(type == TimePartWidget::MINUTE)
+        {
+            ui->widget_Minute->show();
+        }
+        else if(type == TimePartWidget::SECOND)
+        {
+            ui->widget_Second->show();
+        }
+    }
+
+    setQSS();
+}
+
+/* 重置为默认值 */
+void TimePopupWidget::Reset()
+{
+    QDateTime dt = QDateTime::currentDateTime();
+    dt.setTime(QTime(0, 0, 0));
+    ui->widget_Hour->SetTime(dt);
+    ui->widget_Minute->SetTime(dt);
+    ui->widget_Second->SetTime(dt);
+}
+
+
+/* 设置时间 */
+void TimePopupWidget::setTime(const QDateTime& time)
+{
+    m_formerDateTime = time;
+    m_currentDateTime = time;
+    ui->widget_Hour->SetTime(time);
+    ui->widget_Minute->SetTime(time);
+    ui->widget_Second->SetTime(time);
+}
+
+
+/* 设置QSS */
+void TimePopupWidget::setQSS()
+{
+    QString qssPath;
+    if(UIStyle.getUIStyle() == EUIStyle::UI_Light)
+    {
+        qssPath = QString(":/Res/light/timepopupwidget.qss");
+    }
+    else if(UIStyle.getUIStyle() == EUIStyle::UI_Dark)
+    {
+        qssPath = QString(":/Res/dark/timepopupwidget.qss");
+    }
+
+    QFile file(qssPath);
+    if(file.open(QFile::ReadOnly))
+    {
+        QString styleSheet = QLatin1String(file.readAll());
+        setStyleSheet(styleSheet);
+        file.close();
+    }
+    else 
+    {
+        SPDLOG_ERROR("open qss file failed: {}", qssPath.toStdString());
+    }
+}
+
+
+
+/**
+ * @brief 时间列表选中事件
+ * @param item
+ */
+void TimePopupWidget::do_listItemClicked(QListWidgetItem *item)
+{
+    if (nullptr == item) return;
+    TimePartWidget* pWdg = reinterpret_cast<TimePartWidget*>(QObject::sender());
+    if (nullptr == pWdg) return;
+
+    QString data(item->text());
+    if (data.isEmpty()) return; // 过滤空白项
+    // QDateTime oldDt(ui->dateTimeEdit->dateTime());
+    QDateTime oldDt = m_currentDateTime;
+    QTime t(m_currentDateTime.time());
+    switch (pWdg->GetType()) {
+    case TimePartWidget::HOUR: 
+    {
+        t.setHMS(data.toInt(), t.minute(), t.second());
+        break;
+    }
+    case TimePartWidget::MINUTE: 
+    {
+        t.setHMS(t.hour(), data.toInt(), t.second());
+        break;
+    }
+    case TimePartWidget::SECOND: 
+    {
+        t.setHMS(t.hour(), t.minute(), data.toInt());
+        break;
+    }
+    default:
+        break;
+    }
+    if (oldDt.time() != t) {
+        // m_bTimeFlag = true;
+        // ui->dateTimeEdit->setTime(t);
+        m_currentDateTime.setTime(t);
+        emit signal_timeChanged(m_currentDateTime);
+    }
+}
+
+
+/* 点击了确定按钮 */
+void TimePopupWidget::do_pBtn_Ok_Clicked()
+{
+    emit signal_timeChanged(m_currentDateTime);
+    emit signal_closePopup();
+}
+
+/* 点击了取消按钮 */
+void TimePopupWidget::do_pBtn_Cancel_Clicked()
+{
+    m_currentDateTime = m_formerDateTime;
+    emit signal_timeChanged(m_currentDateTime);
+    emit signal_closePopup();
+}
+
+

+ 55 - 0
demo/Component/SelectTime/SelectTime/timepopupwidget.h

@@ -0,0 +1,55 @@
+#ifndef TIMEPOPUPWIDGET_H
+#define TIMEPOPUPWIDGET_H
+
+#include <QWidget>
+#include "timepartwidget.h"
+#include <QDateTime>
+#include <qdatetime.h>
+
+
+
+namespace Ui {
+class TimePopupWidget;
+}
+
+class TimePopupWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit TimePopupWidget(QWidget *parent = nullptr);
+    ~TimePopupWidget();
+
+    /* 初始化 */
+    void Init(const QVector<int> &types);
+    /* 重置为默认值 */
+    void Reset();
+
+    /* 设置时间 */
+    void setTime(const QDateTime& time);
+
+signals:
+    void signal_timeChanged(const QDateTime& dt);
+    /* 点击了确定或取消按钮,关闭弹窗 */
+    void signal_closePopup();
+
+private:
+    /* 设置QSS */
+    void setQSS();
+
+private slots:
+    /* 列表项点击 */
+    void do_listItemClicked(QListWidgetItem* item);
+
+    /* 点击了确定按钮 */
+    void do_pBtn_Ok_Clicked();
+    /* 点击了取消按钮 */
+    void do_pBtn_Cancel_Clicked();
+
+private:
+    Ui::TimePopupWidget *ui;
+    QDateTime m_currentDateTime;
+    QDateTime m_formerDateTime;
+};
+
+#endif // TIMEPOPUPWIDGET_H

+ 152 - 0
demo/Component/SelectTime/SelectTime/timepopupwidget.ui

@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TimePopupWidget</class>
+ <widget class="QWidget" name="TimePopupWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>200</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>4</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="TimePartWidget" name="widget_Hour" native="true"/>
+      </item>
+      <item>
+       <widget class="TimePartWidget" name="widget_Minute" native="true"/>
+      </item>
+      <item>
+       <widget class="TimePartWidget" name="widget_Second" native="true"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_pBtn" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>32</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>4</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>29</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pBtn_Cancel">
+        <property name="minimumSize">
+         <size>
+          <width>52</width>
+          <height>24</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>取消</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pBtn_Ok">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>52</width>
+          <height>24</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>确定</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>TimePartWidget</class>
+   <extends>QWidget</extends>
+   <header location="global">timepartwidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 591 - 0
demo/Component/SelectTime/SelectTime/timewidget.cpp

@@ -0,0 +1,591 @@
+#include "timewidget.h"
+#include "ui_timewidget.h"
+#include <QListWidgetItem>
+#include <QMouseEvent>
+#include <QDebug>
+#include <QSizePolicy>
+#include <QFile>
+#include "timepartwidget.h"
+#include "shadowwidget.h"
+#include "UIStyleManager.h"
+#include "spdlog/spdlog.h"
+#include "timepopupwidget.h"
+
+TimeWidget::TimeWidget(QWidget *parent , ShowType type) :
+    QFrame(parent),
+    ui(new Ui::TimeWidget),
+    m_wdgTimeArea(nullptr),
+    m_pMainWindow(parent),
+    m_type(type)
+{
+    ui->setupUi(this);
+    Init();
+}
+
+
+TimeWidget::TimeWidget(ShowType type) : 
+    QFrame(nullptr),
+    ui(new Ui::TimeWidget),
+    m_wdgTimeArea(nullptr),
+    m_pMainWindow(nullptr),
+    m_type(type)
+{
+    ui->setupUi(this);
+    Init();
+}
+
+TimeWidget::~TimeWidget()
+{
+    delete ui;
+}
+
+// void TimeWidget::CreateTimeVector(const QVector<int> &types)
+// {
+    // ClearVector(m_vecTimePart);
+    // for (auto& type : types) 
+    // {
+    //     TimePartWidget::emSection emType = static_cast<TimePartWidget::emSection>(type);
+    //     if (emType >= TimePartWidget::emSection::MAX_SECTION) {
+    //         continue;
+    //     }
+    //     TimePartWidget* pTmp = new TimePartWidget(this);
+    //     pTmp->Init(emType);
+    //     if (nullptr != pTmp) {
+    //         pTmp->SetMaxWidth(width() / types.count());
+    //         m_vecTimePart.append(pTmp);
+    //     }
+    // }
+// }
+
+// void TimeWidget::ClearVector(QVector<TimePartWidget *> &vec)
+// {
+//     for (auto& pWdg : vec) {
+//         if (nullptr != pWdg) {
+//             delete pWdg;
+//             pWdg = nullptr;
+//         }
+//     }
+//     vec.clear();
+// }
+
+void TimeWidget::SetMainWindow(QWidget* pWidget)
+{
+    if (nullptr != m_pMainWindow) {
+        this->removeEventFilter(m_pMainWindow);
+    }
+    if (nullptr != pWidget) {
+        pWidget->installEventFilter(this);
+    }
+    m_pMainWindow = pWidget;
+}
+
+/* 返回时间 */
+QTime TimeWidget::getTime()
+{
+    return ui->dateTimeEdit->time();
+}
+
+
+/**
+ * @brief 存在时间就返回hh:mm:ss.zzz格式字符串,否则返回提示信息
+ * @return
+ */
+// QString TimeWidget::getTimeStr()
+// {
+//     QString ret(ui->lbl_tip->text());
+//     if (!ui->dateTimeEdit->isHidden()) {
+//         ret = ui->dateTimeEdit->time().toString("hh:mm:ss");//.zzz
+//     }
+//     return ret;
+// }
+/**
+ * @brief 存在返回时间,否则返回00:00:00
+ * @return
+ */
+QTime TimeWidget::getFormTime() const
+{
+    return ui->dateTimeEdit->isHidden() ? QTime(0, 0, 0) : ui->dateTimeEdit->time();
+}
+
+// void TimeWidget::setTime(const QString& t)
+// {
+//     QTime time = QTime::fromString(t, "hh:mm:ss");
+//     ui->dateTimeEdit->setTime(time);
+//     ui->lbl_tip->hide();
+//     ui->dateTimeEdit->show();
+//     UpdatePopupTime(ui->dateTimeEdit->dateTime());//
+// }
+
+void TimeWidget::setTime(const QTime& t)
+{
+    ui->dateTimeEdit->setTime(t);
+    ui->lbl_tip->hide();
+    ui->dateTimeEdit->show();
+    UpdatePopupTime(ui->dateTimeEdit->dateTime());
+}
+
+void TimeWidget::clearTime()
+{
+    ui->dateTimeEdit->setTime(QTime(0, 0, 0));
+    ui->dateTimeEdit->hide();
+    ui->lbl_tip->show();
+}
+
+QString TimeWidget::tipText() const
+{
+    return ui->lbl_tip->text();
+}
+/* 设置时间选择区域的大小,不能超过时间编辑栏的大小,这个主要是防止时间栏太宽,影响美观 */
+void TimeWidget::setTimeAreaWidth(int w)
+{
+    if(w < 0)
+    {
+        m_width = 0;
+    }
+    else if(w > this->width())
+    {
+        m_width = this->width();
+    }
+    else
+    {
+        m_width = w;
+    }
+}
+
+void TimeWidget::showTimeEditArea()
+{
+    this->show();
+    ShowTimeArea(true);
+}
+
+/* 以弹窗的模式模态显示 */
+void TimeWidget::execShow()
+{
+    QEventLoop loop;
+    connect (this, &TimeWidget::signal_close, &loop, &QEventLoop::quit);
+    this->show();
+    ShowTimeArea(true);
+    loop.exec();
+
+    deleteLater();
+}
+
+/* 设置时间图标 */
+void TimeWidget::setIcon(const QString& icon)
+{
+    /* 设置图片适应按钮大小 */
+    QString ss = QString("border-image: url(%1)").arg(icon);
+    ui->btn_tip->setStyleSheet(ss);
+    ui->btn_tip->show();
+}
+
+/* 设置图标显示 */
+void TimeWidget::setIconShow(bool isShow)
+{
+    if(isShow)
+    {
+        ui->btn_tip->show();
+    }else {
+        ui->btn_tip->hide();
+    }
+}
+
+/* 设置图标大小 */
+void TimeWidget::setIconSize(int w, int h)
+{
+    ui->btn_tip->setMinimumSize(w, h);
+    /* 设置为固定大小 */
+    ui->btn_tip->setFixedSize(w, h);
+    // ui->btn_tip->resize(w, h);
+}
+
+/* 设置默认的样式 */
+void TimeWidget::setDefaultStyle()
+{
+    /* 判断显示类型,如果是弹窗直接显示编辑区 */
+    if(m_type == Dialog)
+    {
+        ui->btn_tip->hide();
+        this->resize(136,36);
+//        ShowTimeArea(false);
+        /* 设置编辑栏样式 */
+        // this->setStyleSheet(R"(
+        //     TimeWidget
+        //     {
+        //         padding-left:15px;
+        //         background: #FFFFFF;
+        //         border-radius: 4px;
+        //         border: 1px solid #E6E9F4;
+        //     }
+        // )");
+    }
+}
+
+/* 设置编辑栏大小 */
+void TimeWidget::setEditLine(int w, int h)
+{
+    this->resize(w, h);
+}
+
+/* 设置禁止使用滚轮修改时间 */
+void TimeWidget::setWheelDisabled(bool disabled)
+{
+    m_isDisableWheel = disabled;
+}
+
+/* 设置QSS */
+void TimeWidget::setQSS()
+{
+    QString qssPath;
+    if(UIStyle.getUIStyle() == EUIStyle::UI_Light)
+    {
+        qssPath = ":/Res/light/timewidget.qss";
+    } else {
+        qssPath = ":/Res/dark/timewidget.qss";
+    }
+
+    QFile file(qssPath);
+    if(file.open(QFile::ReadOnly))
+    {
+        QString styleSheet = QLatin1String(file.readAll());
+        setStyleSheet(styleSheet);
+        file.close();
+    }
+    else 
+    {
+        SPDLOG_ERROR("open qss file failed: {}", qssPath.toStdString());
+    }
+}
+
+/**
+ * @brief 点击提示信息
+ */
+void TimeWidget::onBtnTipClicked()
+{
+    bool isSelected = ui->btn_tip->property("selected").toBool();
+    if (!isSelected) {
+        // 显示日期
+        ui->lbl_tip->hide();
+        ui->dateTimeEdit->show();
+        ShowTimeArea(true);
+    } else {
+        if(m_isDisableClear) { return; } // 如果禁止清除时间,就不执行清除操作
+        // 清除时间
+        ui->dateTimeEdit->setTime(QTime(0, 0, 0));
+        UpdateProperty(ui->btn_tip, "selected", false);
+        QDateTime dt;
+        dt.setTime(QTime(0, 0, 0));
+        UpdatePopupTime(dt);
+        ShowTimeArea(false);
+        ui->dateTimeEdit->hide();
+        ui->lbl_tip->show();
+    }
+}
+
+/**
+ * @brief 这里添加了两个信号,一个是修改过的新时间,一个是旧时间
+ * @param obj
+ * @param e
+ * @return
+ */
+bool TimeWidget::eventFilter(QObject* obj, QEvent* e)
+{
+    if (obj == ui->dateTimeEdit) 
+    {
+        if(e->type() == QEvent::Wheel && m_isDisableWheel)
+        {
+            // 禁止滚轮修改时间
+            return true;
+        }
+        if (e->type() == QEvent::FocusIn && m_type == EditLine)
+        {
+            /* 如果Popup正在关闭 */
+            if(m_isBanPopupShow == true)
+            {
+                m_isBanPopupShow = false;
+                return QWidget::eventFilter(obj, e);
+            }
+            //qInfo() << "dateTimeEdit focusIn";
+            ShowTimeArea(true);
+            UpdateProperty(ui->btn_tip, "selected", true);
+            emit signal_formerTimer(ui->dateTimeEdit->time());
+        }
+        return QWidget::eventFilter(obj, e);
+    } else if (obj == ui->lbl_tip) 
+    {
+        if (e->type() == QEvent::MouseButtonPress && m_type == EditLine)
+        {
+            //qInfo() << "mouseButtonPress";
+            ui->dateTimeEdit->show();
+            ui->lbl_tip->hide();
+            ShowTimeArea(true);
+            //ui->dateTimeEdit->setFocus();//
+            return QWidget::eventFilter(obj, e);
+        }
+    } else if (obj == this) {
+        if (e->type() == QEvent::Enter) {
+            UpdateProperty(this, "hover", true);
+        } else if (e->type() == QEvent::Leave &&
+                   ((m_wdgTimeArea.isNull() && !ui->dateTimeEdit->hasFocus()) ||
+                    (m_wdgTimeArea && m_wdgTimeArea->isHidden())) ) {
+            UpdateProperty(this, "hover", false);
+        }
+    }
+    /* 判断是不是显示区外面,是的话就隐藏 */
+    QMouseEvent* pMouse = reinterpret_cast<QMouseEvent*>(e);
+    if (nullptr != pMouse) 
+    {
+        if (pMouse->type() == QEvent::MouseButtonPress) 
+        {
+            //qInfo() << "focusOut";
+            QPoint gtl = this->mapToGlobal(rect().topLeft());
+            QRect rc(gtl.x(), gtl.y(), width(), height()); // 全局位置判断
+            if (!rc.contains(pMouse->globalPos())) 
+            {
+                if(m_wdgTimeArea != nullptr && !m_wdgTimeArea->isHidden())
+                {
+                    m_isBanPopupShow = true;
+                }
+                
+                ui->dateTimeEdit->clearFocus();
+                ShowTimeArea(false);
+                UpdateProperty(this, "hover", false);
+                /* 关闭显示,发送携带时间的信号 */
+                emit signal_nowTime(ui->dateTimeEdit->time());
+                if(m_type == Dialog)
+                {
+                    this->close();
+                }
+            }
+        }
+    }
+
+    return QWidget::eventFilter(obj, e);
+}
+/**
+ * @brief m_wdgTimeArea跟随时间栏移动
+ * @param event
+ */
+void TimeWidget::moveEvent(QMoveEvent *event)
+{
+    if(m_type == Dialog && m_wdgTimeArea != nullptr)
+    {
+        QPoint pt = this->mapTo(m_pMainWindow, QPoint(0, 0));
+        m_wdgTimeArea->move(QPoint(pt.x() - SHADOW_MARGIN, pt.y() + this->height()));
+//        qDebug() << "posX:" << pt.x() << "posY:" << pt.y();
+    }
+}
+/**
+ * @brief 时间列表选中事件
+ * @param item
+ */
+// void TimeWidget::onListItemClicked(QListWidgetItem *item)
+// {
+//     if (nullptr == item) return;
+//     TimePartWidget* pWdg = reinterpret_cast<TimePartWidget*>(QObject::sender());
+//     if (nullptr == pWdg) return;
+
+//     QString data(item->text());
+//     if (data.isEmpty()) return; // 过滤空白项
+//     QDateTime oldDt(ui->dateTimeEdit->dateTime());
+//     QTime t(ui->dateTimeEdit->time());
+//     switch (pWdg->GetType()) {
+//     case TimePartWidget::HOUR: {
+//         t.setHMS(data.toInt(), t.minute(), t.second());
+//         break;
+//     }
+//     case TimePartWidget::MINUTE: {
+//         t.setHMS(t.hour(), data.toInt(), t.second());
+//         break;
+//     }
+//     case TimePartWidget::SECOND: {
+//         t.setHMS(t.hour(), t.minute(), data.toInt());
+//         break;
+//     }
+//     default:
+//         break;
+//     }
+//     if (oldDt.time() != t) {
+//         m_bTimeFlag = true;
+//         ui->dateTimeEdit->setTime(t);
+//     }
+// }
+
+
+void TimeWidget::do_dateTimeChanged(const QDateTime& dt)
+{
+    ui->dateTimeEdit->setTime(dt.time());
+}
+
+
+/**
+ * @brief QDateTimeEdit控件时间改变事件
+ * @param dt
+ */
+void TimeWidget::onDateTimeChanged(const QDateTime& dt)
+{
+    if (dt.time() != QTime(0, 0, 0)) {
+        UpdateProperty(ui->btn_tip, "selected", true);
+    }
+    // 同步到popupWidget
+    if (!m_bTimeFlag) {
+        UpdatePopupTime(dt);
+    }
+    m_bTimeFlag = false;
+}
+
+/* 关闭Popup弹窗 */
+void TimeWidget::do_closePopup()
+{
+    m_isBanPopupShow = true;
+    ui->dateTimeEdit->clearFocus();
+    ShowTimeArea(false);
+    UpdateProperty(this, "hover", false);
+    /* 关闭显示,发送携带时间的信号 */
+    emit signal_nowTime(ui->dateTimeEdit->time());
+    if(m_type == Dialog)
+    {
+        this->close();
+    }
+}
+
+
+void TimeWidget::UpdateProperty(QObject* obj, const char *name, bool flag)
+{
+    if (nullptr == obj || nullptr == name) {
+        return;
+    }
+    obj->setProperty(name, flag);
+    QWidget* pWdg = qobject_cast<QWidget*>(obj);
+    if (nullptr != pWdg) {
+        this->style()->unpolish(pWdg);
+        this->style()->polish(pWdg);
+    }
+}
+/**
+ * @brief 更新popup列表选中时间
+ * @param dt
+ */
+void TimeWidget::UpdatePopupTime(const QDateTime& dt)
+{
+    // 如果时间列表还没初始化就不会设置时间了
+    if(m_pTimePopupWidget == nullptr)
+    {
+        return;
+    }
+    m_pTimePopupWidget->setTime(dt);
+    // for (int i = 0; i < m_vecTimeSections.size(); ++i) 
+    // {
+    //     auto type = m_vecTimeSections.at(i);
+    //     TimePartWidget::emSection emType = static_cast<TimePartWidget::emSection>(type);
+    //     if (emType >= TimePartWidget::emSection::MAX_SECTION) {
+    //         continue;
+    //     }
+    //     if (i < m_vecTimePart.size()) 
+    //     {
+    //         TimePartWidget* pWdg = m_vecTimePart.at(i);
+    //         if (nullptr == pWdg) continue;
+    //         pWdg->SetTime(dt);
+    //     }
+    // }
+}
+
+/**
+ * @brief wdgTimeArea区域是创建出来的,不属于ui区域,他的父类是m_pMainWindow,因此移动的时候需要使用m_pMainWindow的坐标
+ * @param bShow
+ */
+void TimeWidget::ShowTimeArea(bool bShow)
+{
+    if (m_wdgTimeArea.isNull()) 
+    {
+        CreatePopupWidget();
+    }
+    if (!m_wdgTimeArea.isNull()) 
+    {
+        if (bShow) 
+        {
+            //UpdatePopupTime(ui->dateTimeEdit->dateTime());
+            // 重新定位再显示
+            QPoint pt = this->mapTo(m_pMainWindow, QPoint(0, 0));
+            m_wdgTimeArea->move(QPoint(pt.x() - SHADOW_MARGIN, pt.y() + this->height()));
+            /* 设置选择条的大小,如果没有设置m_width,就是用时间编辑栏的宽度 */
+            m_wdgTimeArea->resize((m_width == 0 ? width() : m_width) + 2 * SHADOW_MARGIN, TIME_AREA_HEIGHT * 6 + 2 * SHADOW_MARGIN);
+            m_wdgTimeArea->setMaximumWidth(width() + 2 * SHADOW_MARGIN);
+            m_wdgTimeArea->show();
+            UpdatePopupTime(ui->dateTimeEdit->dateTime());
+        } else 
+        {
+            m_wdgTimeArea->hide();
+            emit signal_close();
+        }
+    }
+}
+
+void TimeWidget::CreatePopupWidget()
+{
+    // CreateTimeArea
+    m_vecTimeSections = {TimePartWidget::HOUR, TimePartWidget::MINUTE, TimePartWidget::SECOND};
+    // CreateTimeVector(m_vecTimeSections);
+    if(m_pTimePopupWidget == nullptr)
+    {
+        m_pTimePopupWidget = new TimePopupWidget();
+        m_pTimePopupWidget->Init(m_vecTimeSections);
+        connect(m_pTimePopupWidget, &TimePopupWidget::signal_timeChanged, this, &TimeWidget::do_dateTimeChanged);
+        connect(m_pTimePopupWidget, &TimePopupWidget::signal_closePopup, this, &TimeWidget::do_closePopup);
+    }
+    m_wdgTimeArea.reset(new ShadowWidget(m_pMainWindow));
+    if (!m_wdgTimeArea.isNull()) 
+    {
+        if (m_wdgTimeArea->centralWidget() != nullptr) 
+        {
+            m_wdgTimeArea->centralWidget()->setObjectName(QLatin1String("wdg_TimeArea"));
+            m_wdgTimeArea->centralWidget()->setStyleSheet("QWidget#wdg_TimeArea{border-radius: 2px;border: none; }");
+        }
+
+        /* 创建显示时间条的HBox */
+        QHBoxLayout* hLayout = new QHBoxLayout();
+        hLayout->setMargin(1);
+        hLayout->setSpacing(0);
+        m_wdgTimeArea->setCentralLayout(hLayout);
+        if (nullptr == m_wdgTimeArea->getLayout()) 
+        {
+            delete hLayout;
+            hLayout = nullptr;
+        }
+        m_wdgTimeArea->resize(QSize(width() + 2 * SHADOW_MARGIN, TIME_AREA_HEIGHT * 6 + 2 * SHADOW_MARGIN));
+        m_wdgTimeArea->setMaximumWidth(width() + 2 * SHADOW_MARGIN);
+        m_wdgTimeArea->hide();
+
+        if (nullptr != m_wdgTimeArea->getLayout()) 
+        {
+            m_wdgTimeArea->getLayout()->addWidget(m_pTimePopupWidget);
+            // foreach (auto wdg, m_vecTimePart) 
+            // {
+            //     m_wdgTimeArea->getLayout()->addWidget(wdg);
+            //     connect(wdg, &TimePartWidget::sigItemClicked, this, &TimeWidget::onListItemClicked);
+            // }
+        }
+
+    }
+}
+
+/* 初始化函数 */
+void TimeWidget::Init()
+{
+    /* 设置QSS */
+    setQSS();
+    // InitUI
+    ui->dateTimeEdit->hide();
+    ui->dateTimeEdit->installEventFilter(this);
+    this->installEventFilter(this);
+    ui->lbl_tip->installEventFilter(this);
+    if (nullptr != m_pMainWindow) {
+        m_pMainWindow->installEventFilter(this);
+    }
+    ui->btn_tip->setProperty("selected", false);
+
+    connect(ui->btn_tip, &QPushButton::clicked, this, &TimeWidget::onBtnTipClicked);
+    connect(ui->dateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, &TimeWidget::onDateTimeChanged);
+
+    setDefaultStyle();
+}

+ 125 - 0
demo/Component/SelectTime/SelectTime/timewidget.h

@@ -0,0 +1,125 @@
+#ifndef TIMEWIDGET_H
+#define TIMEWIDGET_H
+
+
+
+/**
+ * 使用说明
+ *  1、这个时间选择器支持两种方式
+ *      * 提升QTimeEdit,作为编辑栏修改时间
+ *      * 以弹窗的方式出现
+ *  2、时间选择区域m_wdgTimeArea和时间编辑栏(在UI中)不是统一的,时间选择区域可以点击时间编辑栏
+ *     创建出来,也可以在弹窗中直接显示出来,所以moveEvent事件就是用来移动m_wdgTimeArea的。
+ *  3、在原来的基础上新添加了两个信号,在关闭的时候发送
+ *  4、使用Dialog模式的时候,点击空白处隐藏就会close掉,然后发送新的时间信号
+ *  5、使用Dialog模式,执行execShow()函数,会阻塞运行,直到关闭
+*/
+
+
+
+#include <QFrame>
+#include <QTime>
+
+class TimePartWidget;
+class QListWidgetItem;
+class ShadowWidget;
+class TimePopupWidget;
+
+namespace Ui {
+class TimeWidget;
+}
+
+/* 添加ShowType类型,判断这个控件是编辑栏还是弹窗 */
+class TimeWidget : public QFrame
+{
+    Q_OBJECT
+
+public:
+    enum ShowType{
+        EditLine = 0,           /* 时间编辑栏 */
+        Dialog = 1,             /* 以弹窗的形式出现 */
+    };
+    explicit TimeWidget(QWidget *parent = nullptr , ShowType type = EditLine);
+    explicit TimeWidget(ShowType type = EditLine);
+    ~TimeWidget();
+
+    // void CreateTimeVector(const QVector<int>& types);
+    // void ClearVector(QVector<TimePartWidget*>& vec);
+    // 在父窗口无法容纳控件时,这是必要的
+    void SetMainWindow(QWidget* pWidget);
+    QTime getTime();
+    // QString getTimeStr();
+    QTime getFormTime() const;
+    // void setTime(const QString& t);
+    void setTime(const QTime& t);
+    void clearTime();
+    QString tipText() const;
+    /* 新增一个设置时间条宽度的函数 */
+    void setTimeAreaWidth(int w);
+    /***** 2024-05-25 添加两个信号 ******/
+    void showTimeEditArea();
+    /* 以弹窗的模式模态显示 */
+    void execShow();
+    /* 设置时间图标 */
+    void setIcon(const QString& icon);
+    /* 设置图标显示 */
+    void setIconShow(bool isShow);
+    /* 设置图标大小 */
+    void setIconSize(int w, int h);
+    /* 设置默认的样式 */
+    void setDefaultStyle();
+    /* 设置编辑栏大小 */
+    void setEditLine(int w, int h);
+    /* 设置禁止使用滚轮修改时间 */
+    void setWheelDisabled(bool disabled);
+    /* 禁止点击时间图标清空时间信息 */
+    void setDisableClear(bool disabled) { m_isDisableClear = disabled; }
+
+    /* 设置QSS */
+    void setQSS();
+signals:
+    void signal_nowTime(const QTime& time);
+    void signal_formerTimer(const QTime& time);
+    void signal_close();
+
+protected:
+    bool eventFilter(QObject* obj, QEvent* e) override;
+    void moveEvent(QMoveEvent *event) override;
+
+
+private slots:
+    void onBtnTipClicked();
+    // void onListItemClicked(QListWidgetItem* item);
+    void do_dateTimeChanged(const QDateTime& dt);
+    void onDateTimeChanged(const QDateTime& dt);
+    /* 关闭Popup弹窗 */
+    void do_closePopup();
+private:
+    void UpdateProperty(QObject* obj, const char* name, bool flag);
+    void UpdatePopupTime(const QDateTime& dt);
+    void ShowTimeArea(bool bShow);
+    void CreatePopupWidget();
+    /* 初始化函数 */
+    void Init();
+private:
+    const int TIME_AREA_WIDTH = 56;
+    const int TIME_AREA_HEIGHT = 32;
+    const int SHADOW_MARGIN = 9;    // 对应BlurRadius模糊半径16px
+
+    Ui::TimeWidget *ui;
+    // QVector<TimePartWidget*> m_vecTimePart;
+    TimePopupWidget* m_pTimePopupWidget = nullptr;
+    QVector<int> m_vecTimeSections;
+    bool m_bTimeFlag{false};                     // 时间更新标志
+    QScopedPointer<ShadowWidget> m_wdgTimeArea;  // 时间选择窗口
+    QWidget* m_pMainWindow;                      // 外层祖辈窗口,能容纳时间控件高度即可(默认父窗口)
+    ShowType m_type;                            /* 显示类型 */
+    int m_width = 0;                            /* TimeArea宽度 */
+
+    bool m_isDisableWheel = false;          // 禁用滚轮修改时间
+    bool m_isDisableClear = false;          // 禁用点击时间图标清空时间信息
+    bool m_isBanPopupShow = false;             /* 禁止Popup显示,这个标志位用于关闭Popup弹窗时设置的,防止QEditLine获取焦点后再显示 */
+
+};
+
+#endif // TIMEWIDGET_H

+ 81 - 0
demo/Component/SelectTime/SelectTime/timewidget.ui

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TimeWidget</class>
+ <widget class="QFrame" name="TimeWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>190</width>
+    <height>43</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true"/>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout_2">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>8</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="lbl_tip">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>请选择</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDateTimeEdit" name="dateTimeEdit">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="buttonSymbols">
+      <enum>QAbstractSpinBox::NoButtons</enum>
+     </property>
+     <property name="displayFormat">
+      <string>hh:mm:ss</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btn_tip">
+     <property name="minimumSize">
+      <size>
+       <width>18</width>
+       <height>18</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>18</width>
+       <height>18</height>
+      </size>
+     </property>
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 15 - 0
demo/Component/SelectTime/main.cpp

@@ -0,0 +1,15 @@
+#include "widget.h"
+
+#include <QApplication>
+#include "loginit.h"
+
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    init_log();
+    
+    Widget w;
+    w.show();
+    return a.exec();
+}

+ 27 - 0
demo/Component/SelectTime/widget.cpp

@@ -0,0 +1,27 @@
+#include "widget.h"
+#include "./ui_widget.h"
+
+
+#include <QTimer>
+#include <stdlib.h>
+
+#include "spdlog/spdlog.h"
+
+
+Widget::Widget(QWidget *parent)
+    : QWidget(parent)
+    , ui(new Ui::Widget)
+{
+    ui->setupUi(this);
+
+    
+
+    SPDLOG_INFO("***** Qt Library *****");
+}
+
+Widget::~Widget()
+{
+
+    delete ui;
+}
+

+ 27 - 0
demo/Component/SelectTime/widget.h

@@ -0,0 +1,27 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <QWidget>
+
+
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class Widget; }
+QT_END_NAMESPACE
+
+class Widget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    Widget(QWidget *parent = nullptr);
+    ~Widget();
+
+private slots:
+
+
+private:
+    Ui::Widget *ui;
+
+};
+#endif // WIDGET_H

+ 36 - 0
demo/Component/SelectTime/widget.ui

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="QWidget" name="Widget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>800</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Widget</string>
+  </property>
+  <widget class="TimeWidget" name="timeEdit">
+   <property name="geometry">
+    <rect>
+     <x>120</x>
+     <y>110</y>
+     <width>191</width>
+     <height>26</height>
+    </rect>
+   </property>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>TimeWidget</class>
+   <extends>QTimeEdit</extends>
+   <header location="global">timewidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>