前言
书接上文,这篇文章来谈谈如何在现有的todolist应用中添加日历视图,且除了最常见的月视图外,还包括年视图和周视图。
视图显示
月视图实现
在todolist源码的NewTask界面中,点击选择日期的图标会弹出一个日历视图,其中可以自由选择月份和年份:
可将这一段代码最后的Cancel和OK去掉,并作为月视图放在HomePage中(我将其另存为HomeCalendarView):
qml
//HomePageForm.ui.qml中追加如下代码:
HomeCalendarView {
id: homeCalendarView
width: 260
height: 248
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
}
年视图实现
- 基本思路:将某一年中的12个月的月视图在界面上依次列出,就组成了该年的年视图。
- 具体实现:
月视图的关键在于MonthGrid
,这是Qt Quick内置的一个日历组件,调用它就会显示某年某月的视图,无需手动计算日历构成。
使用前需要先import:
arduino
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
下述代码以2023年为例,且由于篇幅所限,仅展示一月的,读者有需要的可以自行复制粘贴多次或者用循环遍历,修改id值及对应属性和显示的文本。
qml
GridLayout {
id: grid
columns: 2
Rectangle{
width: 150
height: 150
border.color:"black"
border.width: 1
Text {
id: jan
text: qsTr("January")
anchors.margins: 2
}
MonthGrid {
id: monthGrid1
month: Calendar.January
year: 2023
locale: Qt.locale("zh_CN")
anchors.top: jan.bottom
delegate: Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
//opacity: model.month === monthGrid.month ? 1 : 0
text: monthGrid1.locale.toString(model.date, "d")
font: monthGrid1.font
}
}
}
//此处省略剩余11个月的代码
...
}
最终显示效果如下:
周视图实现
- 基本思路 我查看了手机内置的日历应用,发现其周视图就是列出周一至周日,当前是周几就在对应的天数那里打点。依据这个实现,我弄了一个简化版的周视图:
这是通过Text的形式展示的。
- 具体实现 首先需要有周数栏,这可以直接用Qt Quick内置的
DayOfWeekRow
:
qml
DayOfWeekRow {
id:week_row
Layout.fillWidth: true
delegate: Label {
required property string narrowName
color: Constants.secondaryColor
text: narrowName
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
其次,在下面有一个文本框:
qml
Text {
id:week_text
}
两者被放入Rectangle
下的ColumnLayout
布局中。
当相关组件加载完成时,获取当前时间,并获取其中的星期天数信息:
qml
Component.onCompleted:{
var tmp=new Date().toLocaleString(Qt.locale("zh_CN"),Locale.LongFormat)
var str=tmp.substring(11,14)
week_text.text="今天是:" + str
}
视图获取
基础知识
在成功定义了年视图和周视图后,还需要考虑应该如何让用户在需要它时获取到它(而不是将它一股脑塞在首页)。这就涉及到了页面切换的操作。
在Qt中,页面切换有两种基本思路:
- StackView
通俗理解:StackView就是每进入一个页面,就将当前页面压入栈中,按返回时,就将当前页面pop出来。源码中从主页a跳转到设置页b,设置页中又设置若干个子选项以供跳转采用的就是这种方式。
- Loader
通俗理解:Loader,顾名思义,加载组件。其基本思路就是比如定义了好几个组件abc,需要显示a的时候就加载a,bc隐藏,需要显示b、c的时候同理。类似于前端某个页面中局部视图切换时的显示-隐藏思路。
具体实现
- 在Settings.qml中,定义两个点击按钮并编写如下槽:
qml
selectWeekView.onClicked:{
stackView.push("WeekView.qml")
}
selectYearView.onClicked:{
stackView.push("YearView.qml")
}
其中,stackView是在源码的App.qml中定义好的:
qml
StackView {
id: stackView
anchors.fill: parent
initialItem: HomePage {
builtInStyles: root.builtInStyles
}
}
- 将WeekView.qml和YearView.qml都改为
Page
形式,并添加以下Header:
qml
header: NavBar {
id: header
visible: true
//YearView.qml为"YearView"
titleText:"WeekView"
previousPageTitle: qsTr("Settings")
backButton.onClicked: {
stackView.pop()
}
}
至此,相关视图的显示和获取均已完成。