1. 程式人生 > 實用技巧 >QML 自定義Calendar控制元件

QML 自定義Calendar控制元件

日曆控制元件是基於 Qt5.x 以上,匯入 QtQuick.Controls.1.2 即可使用。在看我這篇部落格之前,最好選擇 Calendar 按 F1 檢視 Qt Creator 的幫助文件,或者檢視 Calendar 的官方文件所在網頁,因為我這篇部落格也基本上參考的官方文件,只是在其基礎上寫了個 Demo。

一、展示

x先看下效果:

二、屬性、訊號和方法

2.1 屬性

日曆控制元件使用 style:CalendarStyle 設定樣式,常用屬性如下:

  • gridVisible : bool

    網格是否可見。預設為真

  • gridColor : color

    網格線的顏色

  • background : Component

    日曆的背景。日曆的隱式尺寸的計算基於背景的隱式尺寸

  • navigationBar : Component

    導航條的樣式。在日曆的頂部,包含下個月,上個月和選擇的日期 Label

  • dayDelegate : Component

    主要設定日期的樣式

  • dayOfWeekDelegate : Component

    每週的樣式。周天的高度基於隱式的顯示框的高度計算

  • weekNumberDelegate : Component

    週數的樣式。顯示框的隱式寬用來計算週數的寬

下面的資料會提供給 dayDelegate 的元件:

styleData.date 樣式中的日期,屬性為date
styleData.selected 如果為真,日期被選擇 屬性為bool
styleData.index 這個delegate的索引 屬性為int
styleData.valid 日期有效則為真,屬性bool
styleData.today 日期為今天,為真。屬性bool
styleData.visibleMonth 日期在今月,為真,屬性bool
styleData.hovered 滑鼠懸停在這個單元,為真。即使日期無效。屬性bool
styleData.pressed 滑鼠在單元按下,為真,即使日期無效。屬性bool

2.2 訊號

常用訊號如下所示,這裡不做過多介紹,看訊號名就一目瞭然,實在不行檢視官方文件:

// Signals
clicked(date date)
doubleClicked(date date)
hovered(date date)
pressed(date date)
released(date date)

2.3 方法

常用方法(函式)如下所示,這裡也不做過多介紹,詳情檢視官方文件:

// Methods 
showNextMonth()
showNextYear()
showPreviousMonth()
showPreviousYear()

三、程式碼

main.qml:

import QtQuick 2.3
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4

Rectangle {
    visible: true
    width: 400
    height: 440

    // 定時器:用於延時
    Timer {
        id: timer
    }

    // 計算兩個時間之間的天數
    function getDays() {
        var curDate = new Date();   // 當前日期
        var endDate = calendar.selectedDate -12*60*60*1000 // 結束日期
        var day = (endDate - curDate)/1000/60/60/24
        if(day > -1.0)
            return parseInt(day+1);
        else
            return parseInt(day);
    }

    // 延時函式
    function delay(delayTime, cb) {
        timer.interval = delayTime;
        timer.repeat = false;
        timer.triggered.connect(cb);
        timer.start();
    }

    // 獲得剩餘天數(curDate 到 endDate)
    function getRemainDay() {
        var remainDay = 10
        return remainDay
    }

    // MouseArea的層級在"其它所有控制元件"之下(因為寫在"其它所有控制元件"的後面,又是同級的)
    MouseArea{
        anchors.fill: parent
        onPressed: parent.forceActiveFocus() // 強制讓視窗獲得焦點
    }

    TextField {
        id: textAreaEnd
        width: 320
        height: 40
        placeholderText: "請選擇日期"
        readOnly: true // 只讀
        font.pointSize: 18
        anchors.top: parent.top
        anchors.topMargin: 30
        anchors.horizontalCenter: parent.horizontalCenter

        // 檢測焦點是否在文字輸入框中,在則彈出"日曆"
        onFocusChanged: {
            if (activeFocus)
                calendar.visible = true
            else
                calendar.visible = false
        }

        // 避免選擇日期後"日曆"隱藏,焦點此時還在"文字框"上,無法進入"焦點改變事件"顯示"日曆"的情況
        MouseArea {
            anchors.fill: parent
            onClicked: {
                calendar.visible = true
                parent.forceActiveFocus()
            }
        }
    }

    // 日曆控制元件
    Calendar {
        id: calendar
        anchors.top: textAreaEnd.bottom
        anchors.left: textAreaEnd.left
        width: textAreaEnd.width
        height: 320
        visible: false
        minimumDate: new Date()

        // 日曆樣式
        style: CalendarStyle {
            gridVisible: false // 網格不可見


            // 設定日期的樣式
            dayDelegate: Rectangle {

                // 日期是否為今天
                property bool bIsToday: styleData.date.toLocaleString(Qt.locale("de_DE"), "yyyy-MM-dd") ===
                                        (new Date()).toLocaleString(Qt.locale("de_DE"), "yyyy-MM-dd")

                gradient: Gradient {
                    GradientStop {
                        position: 0.00
                        color: styleData.selected && styleData.date >= new Date() ? "SlateGray" : "white"
                    }
                }

                Label {
                    id: labDay
                    text: styleData.date.getDate()
                    font.family: "Microsoft YaHei"
                    font.pixelSize: 16
                    anchors.centerIn: parent
                    color: (styleData.date > new Date() && styleData.selected) ? "white" :
                           ((styleData.date > new Date() && styleData.visibleMonth)
                           ? (bIsToday ? "blue" : "black") : "Silver")
                }
            }
        }

        // 選擇結束日期之後,隱藏日曆
        onClicked: {
            textAreaEnd.text = Qt.formatDateTime(calendar.selectedDate, "yyyy-MM-dd")            

            // 延時一會兒才隱藏日曆(第二個引數為"函式")
            delay(200, function() {calendar.visible = false})
        }
    }
}

實現功能:

  • 設定日曆控制元件的今天前的日期為"不可選狀態";

  • 點選 TextField 彈出日曆,點選視窗空白區域隱藏日曆;

  • 選擇日期之後,延時隱藏日曆;

  • 計算今天與選擇日期之間的天數。

四、程式碼下載

GitHub 下載連結:https://github.com/confidentFeng/QML_Demo/tree/master/CalendarUse


參考:

QML型別說明-CalendarStyle-翻譯

Qml日曆

QML2.0下的豐富的控制元件之日曆

QML QtQuick.Controls 1 Calendar日曆樣式自定義