Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. MonthGrid.clicked() behavior
Forum Updated to NodeBB v4.3 + New Features

MonthGrid.clicked() behavior

Scheduled Pinned Locked Moved Solved QML and Qt Quick
6 Posts 3 Posters 711 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by
    #1

    Hi all -

    Here's the code:

    class ScheduleModel : public QAbstractListModel
    {
        Q_INVOKABLE void datePicked(QDateTime date) {
            qDebug() << __PRETTY_FUNCTION__ << "date picked:" << date; 
        }
    ...
    

    and:

    MonthGrid {
        id: monthGrid
        onClicked: (date) => {
                       console.log("date clicked is " + date)
                       scheduleModel.datePicked(date)
                   }
    ...
    

    Everything seems to work, but the output is a bit curious: if I click on August 16 2023, here's what I get:

    qml: date clicked is Tue Aug 15 17:00:00 2023 GMT-0700
    void ScheduleModel::datePicked(QDateTime) date picked: QDateTime(2023-08-15 17:00:00.000 Pacific Daylight Time Qt::LocalTime)
    

    I'm not sure how to interpret this - I guess the date/time returned is the first second of the 16th, but to represent it as the 15th strikes me as a little weird. I guess this is just how it works?

    If I change my QDateTime to a QDate in my C++, the qDebug() outputs the correct date.

    Anyway, I'm only posting this because I'm curious if I'm doing it right - comments welcome.

    Thanks...

    JonBJ L 2 Replies Last reply
    0
    • mzimmersM mzimmers

      Hi all -

      Here's the code:

      class ScheduleModel : public QAbstractListModel
      {
          Q_INVOKABLE void datePicked(QDateTime date) {
              qDebug() << __PRETTY_FUNCTION__ << "date picked:" << date; 
          }
      ...
      

      and:

      MonthGrid {
          id: monthGrid
          onClicked: (date) => {
                         console.log("date clicked is " + date)
                         scheduleModel.datePicked(date)
                     }
      ...
      

      Everything seems to work, but the output is a bit curious: if I click on August 16 2023, here's what I get:

      qml: date clicked is Tue Aug 15 17:00:00 2023 GMT-0700
      void ScheduleModel::datePicked(QDateTime) date picked: QDateTime(2023-08-15 17:00:00.000 Pacific Daylight Time Qt::LocalTime)
      

      I'm not sure how to interpret this - I guess the date/time returned is the first second of the 16th, but to represent it as the 15th strikes me as a little weird. I guess this is just how it works?

      If I change my QDateTime to a QDate in my C++, the qDebug() outputs the correct date.

      Anyway, I'm only posting this because I'm curious if I'm doing it right - comments welcome.

      Thanks...

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @mzimmers
      Well, you know what this is all about because of the funny country you live in ;-) We own "proper" time here in England (UTC/GMT), you colonials have to do timezone adjustments as a penalty for living in a backwater :)

      The full datetime being returned is clearly August 16 at 00:00:00 midnight. Doubtless because it's only a date picker, not datetime, so it picks 0 for the hour part. Then you are in EST, which is -05:00 hours back, i.e. 17:00:00 on previous day, August 15th.

      So you are showing a UTC/GMT midnight time in your local time. Meanwhile, if you use QDate instead of QDateTime it appears that does not converted for timezone since it has no time, hence you get to see the original date of 16th August.

      As you are aware I don't know what facilities you have in QML. But you need to do something about not treating the original as 00:00:00 UTC/GMT and then displaying it converted to local time. Perhaps from JavaScript you should be doing something more sophisticated than just printing date, it may well have some timezone aware methods?

      P.S.
      I'm not prepared to go through the previous exactly, but I note that actually Pacific Time seems to be involved here, which is actually UTC-07:00 hours rather than EST which is -05:00 hours. Not to mention, there is daylight time involved here, which should make it -06:00 hours. But you get the drift.....

      mzimmersM 1 Reply Last reply
      2
      • mzimmersM mzimmers

        Hi all -

        Here's the code:

        class ScheduleModel : public QAbstractListModel
        {
            Q_INVOKABLE void datePicked(QDateTime date) {
                qDebug() << __PRETTY_FUNCTION__ << "date picked:" << date; 
            }
        ...
        

        and:

        MonthGrid {
            id: monthGrid
            onClicked: (date) => {
                           console.log("date clicked is " + date)
                           scheduleModel.datePicked(date)
                       }
        ...
        

        Everything seems to work, but the output is a bit curious: if I click on August 16 2023, here's what I get:

        qml: date clicked is Tue Aug 15 17:00:00 2023 GMT-0700
        void ScheduleModel::datePicked(QDateTime) date picked: QDateTime(2023-08-15 17:00:00.000 Pacific Daylight Time Qt::LocalTime)
        

        I'm not sure how to interpret this - I guess the date/time returned is the first second of the 16th, but to represent it as the 15th strikes me as a little weird. I guess this is just how it works?

        If I change my QDateTime to a QDate in my C++, the qDebug() outputs the correct date.

        Anyway, I'm only posting this because I'm curious if I'm doing it right - comments welcome.

        Thanks...

        L Offline
        L Offline
        lemons
        wrote on last edited by
        #3

        @mzimmers here a simple calendar of my QML component collection:

        // main.qml
        ApplicationWindow {
            width: 640
            height: 640
            visible: true
        
            Button {
                anchors.centerIn: parent
                text: "Open Calendar"
                onClicked: calendar.open()
            }
        
            CalendarInput {
                id: calendar
        
                // you can set any date
                selectedDate: new Date()
        
                // to be used as dateFrom or dateTo input
                // to include or exclude the selected day
                // CalendarInput.DayType.EndOfDay
                // CalendarInput.DayType.StartOfDay
                dateType: CalendarInput.DayType.StartOfDay
        
                // limit year selection
                yearFrom: 2018
                yearTo: 2027
        
                // styling
                backgroundColor: "#F9F9F9"
                headerPointSize: 22
                defaultPointSize: 12
                accentColor: "teal"
                textColorOnAccent: "white"
                fontColor: "#2C2E35"
        
                // called once the "confirm" button is clicked
                onConfirm: {
                    console.debug("Date:", selectedDate)
                    console.debug("UNIX Timestamp:", unix)
                }
            }
        }
        
        // CalendarInput.qml
        
        import QtQuick 2.15
        import QtQuick.Window 2.15
        import QtQuick.Controls 2.15
        import QtQuick.Layouts 1.15
        import Qt.labs.calendar 1.0
        
        Popup {
            id: calendar
            // center calendar popup in main window/overlay
            parent: Overlay.overlay ? Overlay.overlay : Window.contentItem
            anchors.centerIn: parent
        
            width: 500
            height: 500
        
            background: Rectangle {
                color: backgroundColor
                radius: 10
            }
        
            // only close calendar via the provided buttons
            closePolicy: Popup.NoAutoClose
            modal: true
        
            // enum for dayType, which gets applied onOpen and before onConfirm
            enum DayType {
                StartOfDay,
                EndOfDay
            }
            // set default dateType to StartOfDay
            property int dateType: CalendarInput.DayType.StartOfDay
        
            // uses setHours instead of setUTCHours as calendar is localized
            function applyDayType() {
                let _date = selectedDate
                if (dateType === CalendarInput.DayType.StartOfDay)
                    _date.setHours(0, 0, 0, 0)
                else
                    _date.setHours(23, 59, 59, 999)
                selectedDate = _date
            }
        
            // background color of calendar popup
            property color backgroundColor: "#F9F9F9"
        
            // pointSize of month-year label
            property int headerPointSize: 22
        
            // default pointSize of texts
            property int defaultPointSize: 12
        
            // background color for highlighting selected date
            property color accentColor: "#017EAF"
        
            // text color for accent background
            property color textColorOnAccent: "white"
        
            // general font color for all texts
            property color fontColor: "#2C2E35"
        
            // selected date the calendar gets initialized with
            property date selectedDate: new Date()
        
            // read the unix timestamp of the selectedDate
            readonly property int unix: selectedDate.getTime() / 1000
        
            // year select list begin
            // default : epoch
            property int yearFrom: 1970
        
            // year select list end
            // default : current year
            property int yearTo: new Date().getFullYear()
        
            // hidden properties; should not be visible from outside
            QtObject {
                id: privateProperties
                property date initialDate
            }
        
            onOpened: {
                // apply day type StartOfDay | EndOfDay (00:00:00 | 23:59:59)
                applyDayType()
                // save inital date for restoring, in case user clicks cancel
                privateProperties.initialDate = selectedDate
                calendar.forceActiveFocus()
            }
        
            // signals for calendar
            // e.g. onConfirm:{myDateProp = selectedDate}
            signal confirm
            signal cancel
        
            // apply selected date to grid date so grid will show month
            // with selected date, if calendar gets reopend
            onConfirm: {
                monthGrid.gridDate = selectedDate
                calendar.close()
            }
        
            // reset grid date and selected date, if user clicks cancel
            onCancel: {
                monthGrid.gridDate = privateProperties.initialDate
                selectedDate = privateProperties.initialDate
                calendar.close()
            }
        
            // update year range if it got changed
            onYearFromChanged: yearList.applyYearRange()
            onYearToChanged: yearList.applyYearRange()
        
            // toggles month-year select
            function showYearSelect(show) {
                yearSelect.visible = show
            }
        
            // gets visible if user clicks the month-year label above date grid
            // simple selection of month and year via 2 ListViews
            ColumnLayout {
                id: yearSelect
                visible: false
                anchors.fill: parent
                anchors.margins: 20
                RowLayout {
                    ListView {
                        id: monthList
                        clip: true
                        Layout.fillHeight: true
                        Layout.fillWidth: true
        
                        // show selected item in the center
                        preferredHighlightBegin: height / 2
                        preferredHighlightEnd: height / 2
                        highlightRangeMode: ListView.StrictlyEnforceRange
                        currentIndex: monthGrid.month
        
                        spacing: 10
        
                        // 12 months
                        model: 12
                        delegate: Rectangle {
                            width: monthList.width
                            height: monthName.height * 1.25
                            color: monthGrid.month === index ? accentColor : "transparent"
                            radius: 5
                            Text {
                                id: monthName
                                anchors.centerIn: parent
                                width: parent.width - 20
                                horizontalAlignment: Text.AlignHCenter
                                font.pointSize: headerPointSize * 0.8
                                wrapMode: Text.Wrap
                                // display month name based on locale (january = 0)
                                text: Qt.locale().monthName(index, Locale.LongFormat)
                                color: monthGrid.month === index ? textColorOnAccent : fontColor
                            }
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    let _date = monthGrid.gridDate
                                    _date.setMonth(index)
                                    monthGrid.gridDate = _date
                                }
                            }
                        }
                    }
                    ListView {
                        id: yearList
                        clip: true
                        Layout.fillHeight: true
                        Layout.fillWidth: true
        
                        spacing: 10
                        model: []
                        preferredHighlightBegin: height / 2
                        preferredHighlightEnd: height / 2
                        highlightRangeMode: ListView.StrictlyEnforceRange
        
                        // set initial year model based on "yearFrom" and "yearTo"
                        // properties of calendar
                        Component.onCompleted: {
                            applyYearRange()
                        }
        
                        function applyYearRange() {
                            let _model = []
                            let _currentIndex = 0
                            for (var i = yearFrom; i <= yearTo; i++) {
                                _model.push(i)
                                if (i === monthGrid.year)
                                    _currentIndex = _model.length - 1
                            }
                            model = _model
                            currentIndex = _currentIndex
                        }
        
                        // update current index for highlighting selected item
                        function updateCurrentIndex() {
                            for (let i in model) {
                                if (model[i] === monthGrid.year) {
                                    currentIndex = i
                                    break
                                }
                            }
                        }
        
                        delegate: Rectangle {
                            width: yearList.width
                            height: year.height * 1.25
                            color: monthGrid.year === modelData ? accentColor : "transparent"
                            radius: 5
                            Text {
                                id: year
                                anchors.centerIn: parent
                                width: parent.width - 20
                                horizontalAlignment: Text.AlignHCenter
                                font.pointSize: headerPointSize * 0.8
                                wrapMode: Text.Wrap
                                text: modelData
                                color: monthGrid.year === modelData ? textColorOnAccent : fontColor
                            }
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    let _date = monthGrid.gridDate
                                    _date.setYear(modelData)
                                    monthGrid.gridDate = _date
                                }
                            }
                        }
                    }
                }
                Text {
                    Layout.alignment: Qt.AlignRight
                    horizontalAlignment: Text.AlignRight
                    font: monthGrid.font
                    text: qsTr("Select date")
                    MouseArea {
                        anchors.fill: parent
                        onClicked: showYearSelect(false)
                    }
                }
            }
        
            GridLayout {
                visible: !yearSelect.visible
                anchors.fill: parent
                anchors.margins: 20
                columns: 1
                rowSpacing: 20
                RowLayout {
                    Layout.fillWidth: true
                    height: monthYearLabel.height * 1.5
                    Image {
                        id: previousMonthIcon
                        verticalAlignment: Qt.AlignVCenter
                        // @svg 'chevron-left' from https://heroicons.com/
                        source: "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\""
                                + fontColor + "\" stroke-width=\"2\">
        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />
        </svg>"
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                monthGrid.addMonths(-1)
                            }
                        }
                    }
        
                    Text {
                        id: monthYearLabel
                        Layout.fillWidth: true
                        verticalAlignment: Qt.AlignVCenter
                        horizontalAlignment: Text.AlignHCenter
                        font.pointSize: headerPointSize
                        // display month name based on locale
                        text: Qt.locale().monthName(
                                  monthGrid.month,
                                  Locale.LongFormat) + " " + monthGrid.year
                        MouseArea {
                            anchors.fill: parent
                            // open month-year select
                            onClicked: showYearSelect(true)
                        }
                    }
        
                    Image {
                        id: nextMonthIcon
                        verticalAlignment: Qt.AlignVCenter
                        // @svg 'chevron-right' from https://heroicons.com/
                        source: "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\""
                                + fontColor + "\" stroke-width=\"2\">
        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />
        </svg>"
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                monthGrid.addMonths(1)
                            }
                        }
                    }
                }
        
                // days of the week based on locale
                DayOfWeekRow {
                    locale: monthGrid.locale
                    Layout.fillWidth: true
        
                    delegate: Text {
                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        text: model.shortName
                        font: monthGrid.font
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }
                }
        
                // month grid displaying the selectable dates
                MonthGrid {
                    id: monthGrid
        
                    locale: Qt.locale()
                    Layout.fillWidth: true
                    Layout.fillHeight: true
        
                    font.pointSize: defaultPointSize
        
                    // initialize with selected date of calendar
                    property date gridDate: selectedDate
        
                    month: gridDate.getMonth()
                    year: gridDate.getFullYear()
                    // add day property for simplyfication
                    property int day: gridDate.getDate()
        
                    // update year-select current index
                    onYearChanged: yearList.updateCurrentIndex()
        
                    function addMonths(amount) {
                        let _date = gridDate
                        _date.setMonth(_date.getMonth() + (amount))
                        gridDate = _date
                    }
        
                    delegate: Item {
                        id: delegateItem
                        Layout.fillHeight: true
                        Layout.fillWidth: true
        
                        // check if delegate is the selected day of the calendar
                        property bool isSelectedDay: (model.year === selectedDate.getFullYear()
                                                      && model.month === selectedDate.getMonth()
                                                      && model.day === selectedDate.getDate(
                                                          ))
                        Rectangle {
                            anchors.centerIn: parent
                            // smaller side gets base length for highlight circle
                            width: Math.min(parent.width, parent.height)
                            height: width
                            radius: width / 2
                            color: delegateItem.isSelectedDay ? accentColor : "transparent"
                            Text {
                                anchors.centerIn: parent
                                opacity: model.month === monthGrid.month ? 1 : 0.25
                                color: delegateItem.isSelectedDay ? textColorOnAccent : fontColor
                                text: model.day
                                font: monthGrid.font
                            }
                        }
                    }
                    onClicked: {
                        // if user selects date, apply it to selectedDate
                        selectedDate = date
                    }
                }
                RowLayout {
                    Layout.fillWidth: true
                    height: childrenRect.height
                    spacing: 20
                    Row {
                        Layout.fillWidth: true
                        Text {
                            font: monthGrid.font
                            text: qsTr("Today")
                            MouseArea {
                                anchors.fill: parent
                                // set selected date and grid view to "today"
                                onClicked: {
                                    selectedDate = new Date()
                                    monthGrid.gridDate = selectedDate
                                }
                            }
                        }
                    }
                    Row {
                        spacing: 20
                        Text {
                            horizontalAlignment: Text.AlignHCenter
                            font: monthGrid.font
                            text: qsTr("Cancel")
                            MouseArea {
                                anchors.fill: parent
                                // emit cancel() signal of calendar
                                onClicked: calendar.cancel()
                            }
                        }
                        Text {
                            horizontalAlignment: Text.AlignHCenter
                            font: monthGrid.font
                            text: qsTr("Confirm")
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    // apply day type before emitting confirm() signal
                                    applyDayType()
                                    calendar.confirm()
                                }
                            }
                        }
                    }
                }
            }
        
            enter: Transition {
                NumberAnimation {
                    property: "opacity"
                    from: 0.0
                    to: 1.0
                    duration: 180
                }
                NumberAnimation {
                    property: "scale"
                    from: 0
                    to: 1
                    duration: 210
                }
            }
            exit: Transition {
                NumberAnimation {
                    property: "opacity"
                    from: 1.0
                    to: 0.0
                    duration: 150
                }
                SequentialAnimation {
                    NumberAnimation {
                        property: "scale"
                        from: 1
                        to: 0.1
                        duration: 155
                    }
                    NumberAnimation {
                        property: "scale"
                        from: 0.1
                        to: 1
                        duration: 1
                    }
                }
            }
        }
        
        mzimmersM 1 Reply Last reply
        2
        • JonBJ JonB

          @mzimmers
          Well, you know what this is all about because of the funny country you live in ;-) We own "proper" time here in England (UTC/GMT), you colonials have to do timezone adjustments as a penalty for living in a backwater :)

          The full datetime being returned is clearly August 16 at 00:00:00 midnight. Doubtless because it's only a date picker, not datetime, so it picks 0 for the hour part. Then you are in EST, which is -05:00 hours back, i.e. 17:00:00 on previous day, August 15th.

          So you are showing a UTC/GMT midnight time in your local time. Meanwhile, if you use QDate instead of QDateTime it appears that does not converted for timezone since it has no time, hence you get to see the original date of 16th August.

          As you are aware I don't know what facilities you have in QML. But you need to do something about not treating the original as 00:00:00 UTC/GMT and then displaying it converted to local time. Perhaps from JavaScript you should be doing something more sophisticated than just printing date, it may well have some timezone aware methods?

          P.S.
          I'm not prepared to go through the previous exactly, but I note that actually Pacific Time seems to be involved here, which is actually UTC-07:00 hours rather than EST which is -05:00 hours. Not to mention, there is daylight time involved here, which should make it -06:00 hours. But you get the drift.....

          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by mzimmers
          #4

          @JonB said in MonthGrid.clicked() behavior:

          @mzimmers
          Well, you know what this is all about because of the funny country you live in ;-) We own "proper" time here in England (UTC/GMT), you colonials have to do timezone adjustments as a penalty for living in a backwater :)

          Yeah, yeah...who's got the Ryder Cup again? Want to place a bet on this year's edition?

          The full datetime being returned is clearly August 16 at 00:00:00 midnight. Doubtless because it's only a date picker, not datetime, so it picks 0 for the hour part. Then you are in EST, which is -05:00 hours back, i.e. 17:00:00 on previous day, August 15th.

          I'm actually in PDT, not EST, which explains the "17:00:00" which is 7 (not 5) hours behind midnight. So, yeah, as I surmised, it's taking the first instance of the day.

          So you are showing a UTC/GMT midnight time in your local time. Meanwhile, if you use QDate instead of QDateTime it appears that does not converted for timezone since it has no time, hence you get to see the original date of 16th August.

          Ahhh...that makes sense.

          As you are aware I don't know what facilities you have in QML. But you need to do something about not treating the original as 00:00:00 UTC/GMT and then displaying it converted to local time. Perhaps from JavaScript you should be doing something more sophisticated than just printing date, it may well have some timezone aware methods?

          That's worth looking into...thanks for the suggestion.

          EDIT:

          The JS code was a little fussy, but I think I got it working with this:

          onClicked: (date) => {
              var offset = date.getTimezoneOffset()
              var localDate = new Date(date.getTime() + (offset * 60000))
              scheduleModel.datePicked(localDate)
          }
          
          1 Reply Last reply
          1
          • L lemons

            @mzimmers here a simple calendar of my QML component collection:

            // main.qml
            ApplicationWindow {
                width: 640
                height: 640
                visible: true
            
                Button {
                    anchors.centerIn: parent
                    text: "Open Calendar"
                    onClicked: calendar.open()
                }
            
                CalendarInput {
                    id: calendar
            
                    // you can set any date
                    selectedDate: new Date()
            
                    // to be used as dateFrom or dateTo input
                    // to include or exclude the selected day
                    // CalendarInput.DayType.EndOfDay
                    // CalendarInput.DayType.StartOfDay
                    dateType: CalendarInput.DayType.StartOfDay
            
                    // limit year selection
                    yearFrom: 2018
                    yearTo: 2027
            
                    // styling
                    backgroundColor: "#F9F9F9"
                    headerPointSize: 22
                    defaultPointSize: 12
                    accentColor: "teal"
                    textColorOnAccent: "white"
                    fontColor: "#2C2E35"
            
                    // called once the "confirm" button is clicked
                    onConfirm: {
                        console.debug("Date:", selectedDate)
                        console.debug("UNIX Timestamp:", unix)
                    }
                }
            }
            
            // CalendarInput.qml
            
            import QtQuick 2.15
            import QtQuick.Window 2.15
            import QtQuick.Controls 2.15
            import QtQuick.Layouts 1.15
            import Qt.labs.calendar 1.0
            
            Popup {
                id: calendar
                // center calendar popup in main window/overlay
                parent: Overlay.overlay ? Overlay.overlay : Window.contentItem
                anchors.centerIn: parent
            
                width: 500
                height: 500
            
                background: Rectangle {
                    color: backgroundColor
                    radius: 10
                }
            
                // only close calendar via the provided buttons
                closePolicy: Popup.NoAutoClose
                modal: true
            
                // enum for dayType, which gets applied onOpen and before onConfirm
                enum DayType {
                    StartOfDay,
                    EndOfDay
                }
                // set default dateType to StartOfDay
                property int dateType: CalendarInput.DayType.StartOfDay
            
                // uses setHours instead of setUTCHours as calendar is localized
                function applyDayType() {
                    let _date = selectedDate
                    if (dateType === CalendarInput.DayType.StartOfDay)
                        _date.setHours(0, 0, 0, 0)
                    else
                        _date.setHours(23, 59, 59, 999)
                    selectedDate = _date
                }
            
                // background color of calendar popup
                property color backgroundColor: "#F9F9F9"
            
                // pointSize of month-year label
                property int headerPointSize: 22
            
                // default pointSize of texts
                property int defaultPointSize: 12
            
                // background color for highlighting selected date
                property color accentColor: "#017EAF"
            
                // text color for accent background
                property color textColorOnAccent: "white"
            
                // general font color for all texts
                property color fontColor: "#2C2E35"
            
                // selected date the calendar gets initialized with
                property date selectedDate: new Date()
            
                // read the unix timestamp of the selectedDate
                readonly property int unix: selectedDate.getTime() / 1000
            
                // year select list begin
                // default : epoch
                property int yearFrom: 1970
            
                // year select list end
                // default : current year
                property int yearTo: new Date().getFullYear()
            
                // hidden properties; should not be visible from outside
                QtObject {
                    id: privateProperties
                    property date initialDate
                }
            
                onOpened: {
                    // apply day type StartOfDay | EndOfDay (00:00:00 | 23:59:59)
                    applyDayType()
                    // save inital date for restoring, in case user clicks cancel
                    privateProperties.initialDate = selectedDate
                    calendar.forceActiveFocus()
                }
            
                // signals for calendar
                // e.g. onConfirm:{myDateProp = selectedDate}
                signal confirm
                signal cancel
            
                // apply selected date to grid date so grid will show month
                // with selected date, if calendar gets reopend
                onConfirm: {
                    monthGrid.gridDate = selectedDate
                    calendar.close()
                }
            
                // reset grid date and selected date, if user clicks cancel
                onCancel: {
                    monthGrid.gridDate = privateProperties.initialDate
                    selectedDate = privateProperties.initialDate
                    calendar.close()
                }
            
                // update year range if it got changed
                onYearFromChanged: yearList.applyYearRange()
                onYearToChanged: yearList.applyYearRange()
            
                // toggles month-year select
                function showYearSelect(show) {
                    yearSelect.visible = show
                }
            
                // gets visible if user clicks the month-year label above date grid
                // simple selection of month and year via 2 ListViews
                ColumnLayout {
                    id: yearSelect
                    visible: false
                    anchors.fill: parent
                    anchors.margins: 20
                    RowLayout {
                        ListView {
                            id: monthList
                            clip: true
                            Layout.fillHeight: true
                            Layout.fillWidth: true
            
                            // show selected item in the center
                            preferredHighlightBegin: height / 2
                            preferredHighlightEnd: height / 2
                            highlightRangeMode: ListView.StrictlyEnforceRange
                            currentIndex: monthGrid.month
            
                            spacing: 10
            
                            // 12 months
                            model: 12
                            delegate: Rectangle {
                                width: monthList.width
                                height: monthName.height * 1.25
                                color: monthGrid.month === index ? accentColor : "transparent"
                                radius: 5
                                Text {
                                    id: monthName
                                    anchors.centerIn: parent
                                    width: parent.width - 20
                                    horizontalAlignment: Text.AlignHCenter
                                    font.pointSize: headerPointSize * 0.8
                                    wrapMode: Text.Wrap
                                    // display month name based on locale (january = 0)
                                    text: Qt.locale().monthName(index, Locale.LongFormat)
                                    color: monthGrid.month === index ? textColorOnAccent : fontColor
                                }
                                MouseArea {
                                    anchors.fill: parent
                                    onClicked: {
                                        let _date = monthGrid.gridDate
                                        _date.setMonth(index)
                                        monthGrid.gridDate = _date
                                    }
                                }
                            }
                        }
                        ListView {
                            id: yearList
                            clip: true
                            Layout.fillHeight: true
                            Layout.fillWidth: true
            
                            spacing: 10
                            model: []
                            preferredHighlightBegin: height / 2
                            preferredHighlightEnd: height / 2
                            highlightRangeMode: ListView.StrictlyEnforceRange
            
                            // set initial year model based on "yearFrom" and "yearTo"
                            // properties of calendar
                            Component.onCompleted: {
                                applyYearRange()
                            }
            
                            function applyYearRange() {
                                let _model = []
                                let _currentIndex = 0
                                for (var i = yearFrom; i <= yearTo; i++) {
                                    _model.push(i)
                                    if (i === monthGrid.year)
                                        _currentIndex = _model.length - 1
                                }
                                model = _model
                                currentIndex = _currentIndex
                            }
            
                            // update current index for highlighting selected item
                            function updateCurrentIndex() {
                                for (let i in model) {
                                    if (model[i] === monthGrid.year) {
                                        currentIndex = i
                                        break
                                    }
                                }
                            }
            
                            delegate: Rectangle {
                                width: yearList.width
                                height: year.height * 1.25
                                color: monthGrid.year === modelData ? accentColor : "transparent"
                                radius: 5
                                Text {
                                    id: year
                                    anchors.centerIn: parent
                                    width: parent.width - 20
                                    horizontalAlignment: Text.AlignHCenter
                                    font.pointSize: headerPointSize * 0.8
                                    wrapMode: Text.Wrap
                                    text: modelData
                                    color: monthGrid.year === modelData ? textColorOnAccent : fontColor
                                }
                                MouseArea {
                                    anchors.fill: parent
                                    onClicked: {
                                        let _date = monthGrid.gridDate
                                        _date.setYear(modelData)
                                        monthGrid.gridDate = _date
                                    }
                                }
                            }
                        }
                    }
                    Text {
                        Layout.alignment: Qt.AlignRight
                        horizontalAlignment: Text.AlignRight
                        font: monthGrid.font
                        text: qsTr("Select date")
                        MouseArea {
                            anchors.fill: parent
                            onClicked: showYearSelect(false)
                        }
                    }
                }
            
                GridLayout {
                    visible: !yearSelect.visible
                    anchors.fill: parent
                    anchors.margins: 20
                    columns: 1
                    rowSpacing: 20
                    RowLayout {
                        Layout.fillWidth: true
                        height: monthYearLabel.height * 1.5
                        Image {
                            id: previousMonthIcon
                            verticalAlignment: Qt.AlignVCenter
                            // @svg 'chevron-left' from https://heroicons.com/
                            source: "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\""
                                    + fontColor + "\" stroke-width=\"2\">
            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 19l-7-7 7-7\" />
            </svg>"
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    monthGrid.addMonths(-1)
                                }
                            }
                        }
            
                        Text {
                            id: monthYearLabel
                            Layout.fillWidth: true
                            verticalAlignment: Qt.AlignVCenter
                            horizontalAlignment: Text.AlignHCenter
                            font.pointSize: headerPointSize
                            // display month name based on locale
                            text: Qt.locale().monthName(
                                      monthGrid.month,
                                      Locale.LongFormat) + " " + monthGrid.year
                            MouseArea {
                                anchors.fill: parent
                                // open month-year select
                                onClicked: showYearSelect(true)
                            }
                        }
            
                        Image {
                            id: nextMonthIcon
                            verticalAlignment: Qt.AlignVCenter
                            // @svg 'chevron-right' from https://heroicons.com/
                            source: "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\""
                                    + fontColor + "\" stroke-width=\"2\">
            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />
            </svg>"
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    monthGrid.addMonths(1)
                                }
                            }
                        }
                    }
            
                    // days of the week based on locale
                    DayOfWeekRow {
                        locale: monthGrid.locale
                        Layout.fillWidth: true
            
                        delegate: Text {
                            Layout.fillHeight: true
                            Layout.fillWidth: true
                            text: model.shortName
                            font: monthGrid.font
                            horizontalAlignment: Text.AlignHCenter
                            verticalAlignment: Text.AlignVCenter
                        }
                    }
            
                    // month grid displaying the selectable dates
                    MonthGrid {
                        id: monthGrid
            
                        locale: Qt.locale()
                        Layout.fillWidth: true
                        Layout.fillHeight: true
            
                        font.pointSize: defaultPointSize
            
                        // initialize with selected date of calendar
                        property date gridDate: selectedDate
            
                        month: gridDate.getMonth()
                        year: gridDate.getFullYear()
                        // add day property for simplyfication
                        property int day: gridDate.getDate()
            
                        // update year-select current index
                        onYearChanged: yearList.updateCurrentIndex()
            
                        function addMonths(amount) {
                            let _date = gridDate
                            _date.setMonth(_date.getMonth() + (amount))
                            gridDate = _date
                        }
            
                        delegate: Item {
                            id: delegateItem
                            Layout.fillHeight: true
                            Layout.fillWidth: true
            
                            // check if delegate is the selected day of the calendar
                            property bool isSelectedDay: (model.year === selectedDate.getFullYear()
                                                          && model.month === selectedDate.getMonth()
                                                          && model.day === selectedDate.getDate(
                                                              ))
                            Rectangle {
                                anchors.centerIn: parent
                                // smaller side gets base length for highlight circle
                                width: Math.min(parent.width, parent.height)
                                height: width
                                radius: width / 2
                                color: delegateItem.isSelectedDay ? accentColor : "transparent"
                                Text {
                                    anchors.centerIn: parent
                                    opacity: model.month === monthGrid.month ? 1 : 0.25
                                    color: delegateItem.isSelectedDay ? textColorOnAccent : fontColor
                                    text: model.day
                                    font: monthGrid.font
                                }
                            }
                        }
                        onClicked: {
                            // if user selects date, apply it to selectedDate
                            selectedDate = date
                        }
                    }
                    RowLayout {
                        Layout.fillWidth: true
                        height: childrenRect.height
                        spacing: 20
                        Row {
                            Layout.fillWidth: true
                            Text {
                                font: monthGrid.font
                                text: qsTr("Today")
                                MouseArea {
                                    anchors.fill: parent
                                    // set selected date and grid view to "today"
                                    onClicked: {
                                        selectedDate = new Date()
                                        monthGrid.gridDate = selectedDate
                                    }
                                }
                            }
                        }
                        Row {
                            spacing: 20
                            Text {
                                horizontalAlignment: Text.AlignHCenter
                                font: monthGrid.font
                                text: qsTr("Cancel")
                                MouseArea {
                                    anchors.fill: parent
                                    // emit cancel() signal of calendar
                                    onClicked: calendar.cancel()
                                }
                            }
                            Text {
                                horizontalAlignment: Text.AlignHCenter
                                font: monthGrid.font
                                text: qsTr("Confirm")
                                MouseArea {
                                    anchors.fill: parent
                                    onClicked: {
                                        // apply day type before emitting confirm() signal
                                        applyDayType()
                                        calendar.confirm()
                                    }
                                }
                            }
                        }
                    }
                }
            
                enter: Transition {
                    NumberAnimation {
                        property: "opacity"
                        from: 0.0
                        to: 1.0
                        duration: 180
                    }
                    NumberAnimation {
                        property: "scale"
                        from: 0
                        to: 1
                        duration: 210
                    }
                }
                exit: Transition {
                    NumberAnimation {
                        property: "opacity"
                        from: 1.0
                        to: 0.0
                        duration: 150
                    }
                    SequentialAnimation {
                        NumberAnimation {
                            property: "scale"
                            from: 1
                            to: 0.1
                            duration: 155
                        }
                        NumberAnimation {
                            property: "scale"
                            from: 0.1
                            to: 1
                            duration: 1
                        }
                    }
                }
            }
            
            mzimmersM Offline
            mzimmersM Offline
            mzimmers
            wrote on last edited by
            #5

            @lemons thank you for sharing your component. I notice that it uses the Qt.labs version of the calendar. Have you given any thought to migrating to the "new" Qt Calendar?

            L 1 Reply Last reply
            0
            • mzimmersM mzimmers has marked this topic as solved on
            • mzimmersM mzimmers

              @lemons thank you for sharing your component. I notice that it uses the Qt.labs version of the calendar. Have you given any thought to migrating to the "new" Qt Calendar?

              L Offline
              L Offline
              lemons
              wrote on last edited by lemons
              #6

              @mzimmers I actually don't really use the component, I primarily wrote it for learning purpose ...

              Below the changes that should make it work with Qt 6:

              // remove versions to pick up Qt6 magic
              import QtQuick
              import QtQuick.Window
              import QtQuick.Controls
              import QtQuick.Layouts
              // remove Qt.labs.calendar
              
              // ...
              MonthGrid {
                  id: monthGrid
                  // ...
                  // change the onClicked to use formal parameters
                  onClicked: function (date) {
                      // if user selects date, apply it to selectedDate
                      selectedDate = date
                  }
              }
              // ...
              
              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved