Qt6自定义日历选择器

4 篇文章 0 订阅
本文介绍了使用Qt6开发的一个自定义日历选择器,具有多层选择功能,支持触控和鼠标操作。作者分享了JavaScript中属性绑定的深入理解,特别是关于`lastSelectDate`变量的浅拷贝和深拷贝的区别,以及在不同场景下的行为差异。
摘要由CSDN通过智能技术生成

Qt6自定义日历选择器

效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主要特点为:

  1. 选择器分三个层面:日期选择、月份选择、年份选择,三个层面均具备类似Win11选择器的过渡;
  2. 所有层面均支持触摸滑动、鼠标滚动、按键翻页,翻页后内部日期同步高亮;
  3. 当前日期底层高亮,已选日期边框加黑;
  4. 支持日期选错后的恢复。

经验总结

这个日历选择器前前后后搞了近3天时间,终于将代码优化至自我认为比较友好的层度,具体内容不重要,大家花时间都能做出来,主要是想通过这几天的实践总结一下对Js的更深入理解:

  1. Js采用了一种属性绑定的形式,初始化绑定是一种深拷贝,具体代码以及运行结果如下:
property var selectDate: lastSelectDate //当前选择的时间
property var lastSelectDate: new Date() //上一次选择时间
Component.onCompleted: {
        lastSelectDate.setFullYear(lastSelectDate.getFullYear() + 1)
        console.log(selectDate, lastSelectDate)
        //此时selectDate不变,lastSelectDate增加1年
    }
Component.onCompleted: {
        lastSelectDate.setFullYear(lastSelectDate.getFullYear() + 1)
        lastSelectDateChanged()
        console.log(selectDate, lastSelectDate)
        //此时selectDate和lastSelectDate均增加1年
    }
    Component.onCompleted: {
        lastSelectDate= new Date()
        console.log(selectDate, lastSelectDate)
        //此时selectDate和lastSelectDate均变为最新时间
    }
  1. 从上代码可以理解,当lastSelectDate= new Date()时,后台自动运行lastSelectDateChanged(),此时与lastSelectDate绑定的所有属性均更新,然而运行lastSelectDate.setFullYear(lastSelectDate.getFullYear() + 1)时,lastSelectDate指向的栈区并无变化,后台不运行lastSelectDateChanged(),因此相关属性均不更新,但若手动运行lastSelectDateChanged(),则绑定lastSelectDate的所有属性均再一次更新。此处与C++创建qml属性及其类似。参考QtCreartor自动创建属性时的代码:
void TestItem::setItemNameList(const QStringList& newItemNameList)
{
    if (_itemNameList == newItemNameList)
        return;
    _itemNameList = newItemNameList;
    emit itemNameListChanged();
}

主要代码说明

首先创建了3个组件,分别是日期选择窗口、月份选择窗口、年份选择窗口

 Component {
        id: _day
        Rectangle {
            color: background
            ColumnLayout {
                anchors.fill: parent
                DayOfWeekRow {
                    locale: Qt.locale("zh_CN")
                    Layout.fillWidth: true
                    delegate: Text {
                        text: shortName
                        font.bold: true
                        color: "black"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        required property string shortName
                    }
                }
                ListView {
                    id: _listview
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    model: 1200
                    snapMode: ListView.SnapOneItem
                    clip: true
                    spacing: 20
                    currentIndex: (selectDate.getFullYear(
                                       ) - 2000) * 12 + selectDate.getUTCMonth()
                    highlightMoveDuration: 100
                    highlightMoveVelocity: -1
                    highlightRangeMode: ListView.StrictlyEnforceRange
                    delegate: MonthGrid {
                        id: month_grid
                        width: _listview.width
                        height: _listview.height
                        month: index % 12
                        year: 2000 + Math.floor(index / 12)
                        locale: Qt.locale("zh_CN")

                        font {
                            family: "SimHei"
                            pixelSize: 14
                        }
                        delegate: AbstractButton {
                            id: _controlv
                            text: model.day

                            property bool isCurrentDate: _root.selectDate.getFullYear(
                                                             ) === model.date.getFullYear()
                                                         && _root.selectDate.getMonth(
                                                             ) === model.date.getMonth()
                                                         && _root.selectDate.getDate(
                                                             ) === model.date.getDate()

                            background: Rectangle {
                                id: _rect
                                anchors.fill: parent
                                border.width: 2
                                border.color: _controlv.down
                                              || isCurrentDate ? "black" : (_controlv.hovered ? "#888888" : "transparent")
                                color: model.today ? accent : "transparent"
                            }
                            contentItem: Text {
                                font: _controlv.font
                                text: _controlv.text
                                color: _controlv.down
                                       || isCurrentDate ? "black" : (model.month === month_grid.month ? "black" : "#888888")
                                horizontalAlignment: Text.AlignHCenter
                                verticalAlignment: Text.AlignVCenter
                            }

                            onClicked: {
                                _root.selectDate = model.date
                                selectDateChanged()
                            }
                        }
                    }
                    onMovementEnded: {
                        selectDate.setUTCFullYear(
                                    2000 + Math.floor(
                                        _listview.currentIndex / 12))
                        selectDate.setUTCMonth(_listview.currentIndex % 12)
                        selectDateChanged()
                    }
                }
            }
        }
    }
    Component {
        id: _month
        GridView {
            id: _gridview
            model: 1200
            clip: true
            cellHeight: height / 4
            cellWidth: width / 4
            highlightRangeMode: GridView.StrictlyEnforceRange
            preferredHighlightBegin: height / 4
            preferredHighlightEnd: height * 3 / 4
            currentIndex: (selectDate.getFullYear(
                               ) - 2000) * 12 + selectDate.getUTCMonth()
            delegate: AbstractButton {
                id: _controlv
                text: (index % 12 + 1) + "月"
                height: _gridview.height / 4
                width: _gridview.width / 4
                property bool isCurrentYear: ((2000 + Math.floor(
                                                   index / 12)) === selectDate.getUTCFullYear(
                                                  ))
                property bool isCurrentMonth: ((2000 + Math.floor(
                                                    index / 12)) === selectDate.getUTCFullYear(
                                                   ))
                                              && (index % 12 === selectDate.getUTCMonth(
                                                      ))
                background: Rectangle {
                    anchors.fill: parent
                    border.width: 2
                    border.color: _controlv.down
                                  || isCurrentMonth ? "black" : (_controlv.hovered ? "gray" : "transparent")
                    color: currentYearIndex === index ? accent : "transparent"
                }
                contentItem: Text {
                    font: _controlv.font
                    text: _controlv.text
                    color: _controlv.down ? "black" : (isCurrentYear ? "black" : "#888888")
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                }

                onClicked: {
                    selectDate.setUTCFullYear(Math.floor(index / 12) + 2000)
                    selectDate.setUTCMonth(index % 12)
                    selectDateChanged()
                    _stackviewv.pop()
                }
            }
            onMovementEnded: {
                selectDate.setUTCFullYear(2000 + Math.floor(
                                              _gridview.currentIndex / 12))
                selectDate.setUTCMonth(_gridview.currentIndex % 12)
                selectDateChanged()
            }
        }
    }
    Component {
        id: _year
        GridView {
            id: _gridview
            model: 100
            clip: true
            cellHeight: height / 4
            cellWidth: width / 4
            highlightRangeMode: GridView.StrictlyEnforceRange
            preferredHighlightBegin: height / 4
            preferredHighlightEnd: height * 3 / 4
            currentIndex: selectDate.getFullYear() - 2000
            delegate: AbstractButton {
                id: _controlv
                text: (2000 + index) + "年"
                height: _gridview.height / 4
                width: _gridview.width / 4

                property bool isCurrentDecade: ((2000 + index) >= (Math.floor(
                                                                       selectDate.getUTCFullYear()
                                                                       / 10) * 10))
                                               && ((2000 + index)
                                                   <= (Math.floor(selectDate.getUTCFullYear(
                                                                      ) / 10) * 10 + 9))
                property bool isCurrentYear: ((2000 + index) === selectDate.getUTCFullYear(
                                                  ))

                background: Rectangle {
                    anchors.fill: parent
                    border.width: 2
                    border.color: _controlv.down
                                  || isCurrentYear ? "black" : (_controlv.hovered ? "gray" : "transparent")
                    color: currentDecadeIndex === index ? accent : "transparent"
                }
                contentItem: Text {
                    font: _controlv.font
                    text: _controlv.text
                    color: _controlv.down ? "black" : (isCurrentDecade ? "black" : "#888888")
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                }
                onClicked: {
                    selectDate.setUTCFullYear(index + 2000)
                    selectDateChanged()
                    _stackviewv.pop()
                }
            }

            onMovementEnded: {
                selectDate.setUTCFullYear(2000 + _gridview.currentIndex)
                selectDateChanged()
            }
        }
    }

三个窗口通过StackView组件进行切换,每个窗口均需要实现拖拽、滚轮滚动、反面的联动绑定。代码过几天我会发布出来,先记录到这主要是为了总结这几天的收获。

### 回答1: Qt自带的QCalendarWidget类提供了一种简单的日历控件,但是功能上比较基础。如果需要更多功能,可以自定义一个增强版的日历控件。 首先,可以通过继承QCalendarWidget类来创建一个新的自定义日历控件类。然后在新的类中添加一些额外的功能。例如,可以添加一个日期选择范围的功能,让用户只能在指定的日期范围内选择日期。 另外,可以添加一个月份/年份选择器,让用户可以快速切换到其他月份或年份。通过添加一个组合框或者切换按钮来实现这个功能。 还可以增加一个自定义的日期标记功能,让用户可以为某些特定日期添加标记,例如节假日、重要事件等。这样用户在看日历的时候就可以一目了然地知道哪些日期是特殊的。 如果希望日历控件适应不同的主题或者界面风格,还可以添加样式自定义的功能,让用户可以根据自己的需求来设置日历的外观样式。 另外,还可以添加一些其他的功能,如设置默认选择的日期、在某些特定日期显示特定信息等。 总之,通过继承QCalendarWidget类并添加上述功能,我们可以创建一个更加强大和个性化的日历控件,满足各种不同的需求。 ### 回答2: Qt中的日历组件是一个非常实用的工具,但是有时候我们可能需要对其进行一些自定义和增强。以下是关于如何创建一个自定义的增强版Qt日历的一些建议: 1. 自定义外观:通过使用Qt的样式表功能,你可以自定义日历的外观,包括背景颜色、字体、边框等。你可以根据自己的需求来设计一个与应用程序风格一致的日历。 2. 添加额外功能:你可以在日历中添加一些额外的功能,如快速切换到特定日期、显示公众假日等。通过添加自定义的按钮或选项,用户可以方便地选择他们感兴趣的日期和事件。 3. 自定义事件:你可以为特定日期添加自定义事件,如生日、会议等。通过添加事件标记或图标,用户可以轻松地查看和管理他们的日程安排。 4. 跨平台支持:Qt提供了对多个平台的支持,包括 Windows、Linux和MacOS等。确保你的自定义增强版日历在不同平台上都能正常运行和显示。 5. 多语言支持:如果你的应用程序需要支持多种语言环境,你可以使用Qt的国际化功能来实现日历的多语言显示。这样,用户可以根据自己的语言偏好来使用你的应用程序。 6. 响应式设计:确保你的日历在不同窗口尺寸和屏幕分辨率下都能够自适应,并且可以正确地显示和操作。这样,用户无论是在手机、平板还是计算机上使用你的应用程序,都能够获得良好的体验。 通过以上的一些自定义和增强,你可以创建一个更加灵活和强大的Qt日历组件,满足用户的日历需求,并提升应用程序的用户体验。 ### 回答3: Qt是一款功能强大的GUI(图形用户界面)开发框架,它提供了丰富的工具和组件,可以快速轻松地创建各种应用程序。其中,日历是常用的UI控件之一。 自定义日历的增强版是使用Qt框架自定义开发的一个升级版本,具有更多功能和更好的用户体验。 首先,增强版的自定义日历具有丰富的样式选择。用户可以根据自己的喜好和需求选择不同的颜色、字体、背景等等。这样,用户可以根据自己的个性化需求,将日历的外观设置得更加独特和吸引人。 其次,增强版的自定义日历支持更多的交互方式。传统的日历只能通过单击或滚动的方式来选择日期,而增强版的自定义日历可以通过手指滑动、手势缩放等更多的方式来操作。这样,用户可以更加灵活地浏览和选择日期,提升了用户的操作体验。 再次,增强版的自定义日历具有更多的功能。除了基本的日期选择和显示外,增强版的自定义日历也可以提供天气预报、节假日提醒、待办事项等功能。用户可以通过简单的操作,在日历上查看天气信息、添加和管理待办事项等,方便快捷地掌握自己的日程安排。 此外,增强版的自定义日历还可以与其他应用程序进行集成。例如,用户可以将日历与电子邮件或社交媒体应用程序相连,以便在特定日期或活动之前接收提醒或通知。这样,用户可以更好地管理自己的时间和安排。 总之,Qt自定义日历的增强版具有更多的样式选择、交互方式、功能和与其他应用程序的集成,提供了更好的用户体验和更全面的功能。无论是对个人用户还是商业用户来说,这都是一个非常实用和有价值的工具。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值