使用QML Tumbler 实现时间日期选择器

引言

在现代应用程序开发中,时间与日期选择是常见的用户界面需求。无论是在日程安排、预约系统还是任何需要时间录入的场景,一个直观易用的选择器组件可以大大提升用户体验。本文将详细介绍如何使用 QML 技术实现两种常用的选择器组件:时间选择器和日期时间选择器。

相关阅读


项目结构

Main.qml
TimePicker.qml
DateTimePicker.qml
main.cpp
CMakeLists.txt

示例实现与代码解析

本项目实现了两个实用的选择器组件:时间选择器(TimePicker)和日期时间选择器(DateTimePicker)。下面将对这些组件进行详细解析。

示例一:时间选择器(TimePicker)

时间选择器允许用户通过滚动选择特定的小时和分钟值。这种交互方式类似于传统的模拟时钟调整,但提供了更为精确和直观的数字选择。

核心代码:

Rectangle {
    id: root
    width: 280
    height: 400
    color: "#ffffff"
    radius: 10
    border.color: "#e0e0e0"
    border.width: 1

    property int hours: hoursTumbler.currentIndex
    property int minutes: minutesTumbler.currentIndex

    ColumnLayout {
        anchors.fill: parent
        spacing: 10

        Text {
            Layout.alignment: Qt.AlignHCenter
            text: "选择时间"
            font.pixelSize: 20
            color: "#333333"
            Layout.topMargin: 20
        }

        Rectangle {
            Layout.alignment: Qt.AlignHCenter
            Layout.preferredWidth: parent.width - 40
            Layout.preferredHeight: 200
            color: "transparent"

            Row {
                anchors.centerIn: parent
                spacing: 10

                Tumbler {
                    id: hoursTumbler
                    model: 24
                    height: 200
                    width: 80
                    
                    delegate: Text {
                        text: modelData.toString().padStart(2, '0')
                        color: Tumbler.tumbler.currentIndex === index ? "#1976D2" : "#666666"
                        font.pixelSize: Tumbler.tumbler.currentIndex === index ? 22 : 18
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
                    }
                }

                Text {
                    text: ":"
                    font.pixelSize: 24
                    anchors.verticalCenter: parent.verticalCenter
                    color: "#333333"
                }

                Tumbler {
                    id: minutesTumbler
                    model: 60
                    height: 200
                    width: 80

                    delegate: Text {
                        text: modelData.toString().padStart(2, '0')
                        color: Tumbler.tumbler.currentIndex === index ? "#1976D2" : "#666666"
                        font.pixelSize: Tumbler.tumbler.currentIndex === index ? 22 : 18
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
                    }
                }
            }
        }

        Text {
            Layout.alignment: Qt.AlignHCenter
            text: hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0')
            font.pixelSize: 24
            color: "#1976D2"
        }
    }
}

代码解析:

外观设计

  • 使用 Rectangle 作为容器,设置圆角和边框,营造现代化的界面风格
  • 采用简洁的配色方案,主色调为蓝色(#1976D2),与灰色搭配形成对比
  • 整体布局采用垂直方向的 ColumnLayout 排列元素

时间选择逻辑

  • 使用两个 Tumbler 组件分别控制小时(0-23)和分钟(0-59)
  • 通过属性绑定 property int hours: hoursTumbler.currentIndex 直接获取选择的值
  • 实时显示当前选择的时间,方便用户确认

视觉反馈

  • 当前选中项使用突出的蓝色和更大的字体
  • 通过 opacity 属性实现滚轮效果,让远离中心的项逐渐变淡
  • 使用 padStart(2, '0') 确保时间始终以两位数显示(如 “01” 而非 “1”)

示例二:日期时间选择器(DateTimePicker)

日期时间选择器扩展了时间选择的功能,增加了年、月、日的选择,提供了完整的日期时间设置能力。

核心代码:

Rectangle {
    id: root
    width: 320
    height: 480
    color: "#ffffff"
    radius: 10
    border.color: "#e0e0e0"
    border.width: 1

    property date selectedDateTime: new Date()

    function updateDateTime() {
        if (!yearTumbler.currentItem || !dayTumbler.currentItem) return;
        
        let newDate = new Date(selectedDateTime)
        let year = parseInt(yearTumbler.currentItem.text)
        let month = monthTumbler.currentIndex
        let day = parseInt(dayTumbler.currentItem.text)
        let hours = hoursTumbler.currentIndex
        let minutes = minutesTumbler.currentIndex

        // 验证日期是否有效
        if (isNaN(year) || isNaN(day)) return;
        
        newDate.setFullYear(year)
        newDate.setMonth(month)
        newDate.setDate(day)
        newDate.setHours(hours)
        newDate.setMinutes(minutes)
        
        if (newDate.getTime() === selectedDateTime.getTime()) return;
        selectedDateTime = newDate
    }

    // 计算指定年月的天数
    function getDaysInMonth(year, month) {
        return new Date(year, month + 1, 0).getDate()
    }

    Component.onCompleted: {
        let currentDate = new Date()
        yearTumbler.currentIndex = yearTumbler.model.indexOf(currentDate.getFullYear().toString())
        monthTumbler.currentIndex = currentDate.getMonth()
        dayTumbler.currentIndex = currentDate.getDate() - 1
        hoursTumbler.currentIndex = currentDate.getHours()
        minutesTumbler.currentIndex = currentDate.getMinutes()
    }
    
    // ... Tumbler 组件实现 ...

    Text {
        Layout.alignment: Qt.AlignHCenter
        text: selectedDateTime.toLocaleString(Qt.locale(), "yyyy年MM月dd日 hh:mm")
        font.pixelSize: 18
        color: "#1976D2"
    }
}

代码解析:

日期时间管理

  • 使用 property date selectedDateTime 存储完整的日期时间信息
  • 实现 updateDateTime() 函数统一处理所有 Tumbler 的变更
  • 加入错误处理和有效性检查,确保日期合法

月份天数处理

  • 通过 getDaysInMonth() 函数动态计算每月天数
  • 在月份变化时自动调整日期选择器的可选范围
  • 避免出现无效日期(如 2 月 31 日)

初始化与数据绑定

  • Component.onCompleted 中设置初始值为当前系统时间
  • 使用 Qt.callLater() 延迟更新,避免组件初始化时的问题
  • 通过 toLocaleString() 格式化显示完整的日期时间

错误处理与优化

  • 增加空值检查,防止访问空对象属性
  • 添加数据有效性验证,避免设置非法日期
  • 使用日期相等性比较,减少不必要的更新

主窗口整合

在 Main.qml 中,我们将两个选择器组件集成到一个统一的界面中,由于篇幅过长,此处代码省略,详情请看下载链接。

运行效果

日期选择器


总结

本文介绍了使用 QML 实现时间选择器和日期时间选择器的方法与技巧。通过这个项目,我们可以得出以下几点经验:

  • 将 UI 元素封装为独立组件,增强代码复用性和可维护性
  • 加入适当的错误检查和边界条件处理,增强程序健壮性
  • 充分利用 QML 的数据绑定特性,简化状态管理

下载链接

完整项目代码可以从以下链接获取:GitCode - DateTimePicker

GitCode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值