0.前言
QML中QtQuick.Controls 1里有Calendar这个控件,官方的文档以及示例都很简单,网上很多人也是自己重新实现的,我比较懒,照着QtQuick.Controls.Styles里的源码改了下。
(2021-1-7补充)最近又在用这个,发现之前从项目里copy代码出来的时候有些地方没弄好,所以文末补了个新的,色调和Qt默认效果差不多。
1.展示
效果如图:
我是用的Qt 5.9,不过这个控件在低版本里也可以用。还有就是他用的js的Date类,月份是从0开始的,用的时候要+1。代码如下:
//main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id:item_root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
CalendarBox{
width: 300
height: 300
anchors.centerIn: parent
calendar.onSelectedDateChanged:{
}
calendar.onDoubleClicked: {
}
}
}
//CalendarBox.qml
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Rectangle{
width: 300
height: 300
border.width: 1
border.color: Qt.rgba(33/255,104/255,101/255,1)
color: "black"
property alias calendar: the_calendar
//这里没有把字体颜色之类的引出来,作为控件的时候需要定义这些
Calendar{
id:the_calendar
anchors.fill: parent
anchors.margins: 2
style: CalendarStyle {
gridColor: Qt.rgba(18/255,62/255,68/255,1)
//gridVisible: false
background: Rectangle{
id:background
anchors.fill: parent
color:Qt.rgba(18/255,62/255,68/255,1)
}
//标题年月
navigationBar:Item{
//color: "transparent"
height: the_calendar.height/8
Canvas {
id: prevYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = Qt.rgba(100/255,1,1,1)
ctx.beginPath()
ctx.moveTo(0,height*3/4)
ctx.lineTo(width/2,height/4)
ctx.lineTo(width,height*3/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showPreviousYear()
}
}
}
Canvas {
id: nextYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: prevYear.right
anchors.leftMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = Qt.rgba(100/255,1,1,1)
ctx.beginPath()
ctx.moveTo(0,height/4)
ctx.lineTo(width/2,height*3/4)
ctx.lineTo(width,height/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showNextYear()
}
}
}
Label {
id: labelYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: nextYear.right
anchors.leftMargin: 15
//text: the_calendar.selectedDate.getFullYear()+qsTr('年')
text:control.visibleYear+qsTr('年')
//elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
font.pixelSize: 14
font.family: "SimSun"
color: Qt.rgba(101/255,1,1,1)
}
Canvas {
id: nextMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = Qt.rgba(100/255,1,1,1)
ctx.beginPath()
ctx.moveTo(0,height/4)
ctx.lineTo(width/2,height*3/4)
ctx.lineTo(width,height/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showNextMonth()
}
}
}
Canvas {
id: prevMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: nextMonth.left
anchors.rightMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = Qt.rgba(100/255,1,1,1)
ctx.beginPath()
ctx.moveTo(0,height*3/4)
ctx.lineTo(width/2,height/4)
ctx.lineTo(width,height*3/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showPreviousMonth()
}
}
}
Label {
id: labelMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: prevMonth.left
anchors.rightMargin: 15
//注意Date原本的月份是0开始
text: (control.visibleMonth+1)+qsTr('月')
//elide: Text.ElideRight
horizontalAlignment: Text.AlignRight
font.pixelSize: 14
font.family: "SimSun"
color: Qt.rgba(101/255,1,1,1)
}
Rectangle{
width: parent.width
height: 1
anchors.bottom: parent.bottom
color: "black"
}
}
//星期
dayOfWeekDelegate: Item{
//color: "transparent"
height: the_calendar.height/8
Label {
text: control.__locale.dayName(styleData.dayOfWeek, control.dayOfWeekFormat)
anchors.centerIn: parent
color: Qt.rgba(101/255,1,1,1)
font.pixelSize: 12
font.family: "SimSun"
}
}
dayDelegate: Rectangle {
//选中-当月未选中-其他
color: styleData.selected
?Qt.rgba(52/255,142/255,145/255,1)
: (styleData.visibleMonth && styleData.valid
?Qt.rgba(6/255,45/255,51/255,1)
: Qt.rgba(3/255,28/255,35/255,1));
Label {
text: styleData.date.getDate()
anchors.centerIn: parent
font.pixelSize: 12
font.family: "SimSun"
color: styleData.valid
?Qt.rgba(197/255,1,1,1)
: Qt.rgba(16/255,100/255,100/255,1)
}
}
}
}
}
2.更新
使用时可以放到 Dialog 或者 Popup 里
import QtQuick 2.12
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
//日历样式自定义
//龚建波 2021-1-7
Calendar{
id:control
implicitHeight: 280
implicitWidth: 280
//普通色块背景
property color normalBgColor: "#FFFFFF"
//选中项背景
property color selectBgColor: "#305FDE"
//超出月份背景
property color outBgColor: normalBgColor
//不可选背景(最大最小范围外)
property color disableBgColor: "#F0F0F0"
//网格颜色
property color gridColor: "#E5E5E5"
//标题文本颜色
property color darkTextColor: "#242526"
//日期文本颜色
property color lightTextColor: "#555658"
//超出月份文本颜色
property color outTextColor: "#999999"
//不可选文本(最大最小范围外)
property color disableTextColor: "#BBBBBB"
style: CalendarStyle {
gridColor: control.gridColor
//gridVisible: false
background: Rectangle{
id:background
anchors.fill: parent
color: control.normalBgColor
}
//标题年月
navigationBar:Item{
//color: "transparent"
height: control.height/8
Canvas {
id: prevYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = control.darkTextColor
ctx.beginPath()
ctx.moveTo(0,height*3/4)
ctx.lineTo(width/2,height/4)
ctx.lineTo(width,height*3/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showPreviousYear()
}
}
}
Canvas {
id: nextYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: prevYear.right
anchors.leftMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = control.darkTextColor
ctx.beginPath()
ctx.moveTo(0,height/4)
ctx.lineTo(width/2,height*3/4)
ctx.lineTo(width,height/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showNextYear()
}
}
}
Label {
id: labelYear
anchors.verticalCenter: parent.verticalCenter
anchors.left: nextYear.right
anchors.leftMargin: 15
//text: control.selectedDate.getFullYear()+qsTr('年')
text: control.visibleYear+qsTr('年')
//elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
font.pixelSize: 14
font.family: "Microsoft YaHei"
color: control.darkTextColor
}
Canvas {
id: nextMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = control.darkTextColor
ctx.beginPath()
ctx.moveTo(0,height/4)
ctx.lineTo(width/2,height*3/4)
ctx.lineTo(width,height/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showNextMonth()
}
}
}
Canvas {
id: prevMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: nextMonth.left
anchors.rightMargin: 10
width: parent.height/2
height: width
//color: bgColor
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 1
ctx.strokeStyle = control.darkTextColor
ctx.beginPath()
ctx.moveTo(0,height*3/4)
ctx.lineTo(width/2,height/4)
ctx.lineTo(width,height*3/4)
//ctx.closePath()
ctx.stroke()
}
MouseArea{
anchors.fill: parent
onClicked: {
control.showPreviousMonth()
}
}
}
Label {
id: labelMonth
anchors.verticalCenter: parent.verticalCenter
anchors.right: prevMonth.left
anchors.rightMargin: 15
//注意Date原本的月份是0开始
text: (control.visibleMonth+1)+qsTr('月')
//elide: Text.ElideRight
horizontalAlignment: Text.AlignRight
font.pixelSize: 14
font.family: "Microsoft YaHei"
color: control.darkTextColor
}
Rectangle{
width: parent.width
height: 1
anchors.bottom: parent.bottom
color: control.gridColor
}
}
//星期
dayOfWeekDelegate: Item{
//color: "transparent"
height: control.height/8
Label {
text: control.__locale.dayName(styleData.dayOfWeek, control.dayOfWeekFormat)
anchors.centerIn: parent
color: control.darkTextColor
font.pixelSize: 14
font.family: "Microsoft YaHei"
}
}
dayDelegate: Rectangle {
//选中-当月未选中-其他
color: (styleData.selected
? control.selectBgColor
: styleData.valid
? styleData.visibleMonth
? control.normalBgColor
: control.outBgColor
: control.disableBgColor)
Label {
text: styleData.date.getDate()
anchors.centerIn: parent
font.pixelSize: 12
font.family: "Microsoft YaHei"
color: (styleData.selected
? control.normalBgColor
: styleData.valid
? styleData.visibleMonth
? control.lightTextColor
: control.outTextColor
: control.disableTextColor)
}
}
}
}
3.参考文档
Qt文档:5.7\Src\qtquickcontrols\src\controls\Styles\Base\CalendarStyle.qml
Qt文档:5.7\Src\qtquickcontrols\src\controls\Calendar.qml