×
Namespaces

Variants
Actions
Revision as of 04:20, 11 October 2012 by hamishwillee (Talk | contribs)

How to create calendar component using Qt Quick

From Nokia Developer Wiki
Jump to: navigation, search
Featured Article
12 Feb
2012

This article demonstrates how to create a Calendar component using Qt Quick.

Article Metadata
Code Example
Installation file: Media: CalendarQML.sis
Tested with
Devices(s): N8,C7,N950
Compatibility
Platform(s): Symbian^3 and later, Qt 4.7.3 and later, Desktop, MeeGo
Symbian
Platform Security
Signing Required: Self-Signed
Article
Keywords: Calendar
Created: lildeimos (22 Jan 2014)
Last edited: hamishwillee (11 Oct 2012)

Contents

Introduction

Qt Quick provides an user friendly, cross platform and elegant environment for application UI development. To see the kind of rich UI supported by Qt Quick we will create a Calendar application which runs on Desktop, Symbian and MeeGo platform. When the application starts it launches with the current date, month and year in the calendar. User can go to any date, month and year using the date picker option. When user clicks on any of the date the application fetches the selected date, month and year and display in console for further use.

Calendar Current Date
Calendar Date Picker

Implementation

First we create a Hello World Qt Quick project. The main component of the Calendar is build with a Repeater which makes 49 rectangles in a grid. The first 7 represents the days columns, the other 42 are the days of the current month positioned under the respective column day. The unfilled days are greyed and are not animated when hover and they are not selectable.


  Repeater {
id: rep
property real delegateWidth: Math.min(calendar.width, calendar.height) / 7;
width: parent.width
height: parent.height
model: listModel
delegate: Rectangle {
id: rect
property int scaleAnimDuration: 100
x: eval("xEval")
y: eval("yEval") + rep.delegateWidth
opacity: eval("opacityEval")
scale: eval("scaleEval")
width: rep.delegateWidth
height: width
color: {
if (index > 6) {
if (eval("grayedCell"))
return Qt.rgba(0.8,0.8,0.8, 0.7);
if (calendar.day === dayNumberText || index%7===0)
return Qt.rgba(250,0,0, 0.4);
else
return Qt.rgba(115,115,115, 0.4);
}
else
return Qt.rgba(0,100,0, 0.4)
}
border.color: (eval("grayedCell") && index>6 ? "grey" : "white")
radius: 20
enabled: !eval("grayedCell")
Behavior on x { NumberAnimation { duration: 800; easing.type: Easing.InQuad } }
Behavior on y { NumberAnimation { duration: 800; easing.type: Easing.InQuad } }
Behavior on opacity { NumberAnimation { duration: 700; easing.type: Easing.InQuad } }
Behavior on scale { NumberAnimation { duration: scaleAnimDuration; easing.type: Easing.InQuad } }
Text {
id: dayNumber
anchors.fill: parent
text: dayNumberText
font.bold: true
color: (eval("grayedCell") && index>6 ? "grey" : "white")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 21
}
MouseArea {
anchors.fill: rect
hoverEnabled: true
// If scaleAnimDuration=100 the rectangle isn't pressed so we can scale it
// else the animation made onClicked has not the behavior we want
onEntered: if (scaleAnimDuration === 100 && index > 6) rect.scale = 1.2
onExited: if (scaleAnimDuration === 100 && index > 6) rect.scale = 1
onClicked: {
if (dayNumber.text !== "" && index > 6) {
scaleAnimDuration = 700
rect.scale = 3;
spreadOutRectangles(index);
dayPicked(new Date(year, month, dayNumber.text) );
}
}
}
}
}

The Repeater model is filled dynamically by function initListModel(), which also defines the animation of the rectangle and the date in it.

    function initListModel()
{
// Reset ListModel and starting rectangle positions
// First 7 rectangles are the days text
listModel.clear();
for (var i=0; i<49; i++) {
if (i>6)
listModel.append({
"dayNumberText": "",
"dayStringText": "",
"grayedCell": true,
// Other 2 fancy animations, leave uncommented which you want
// "xEval": Math.sin( 360/(i+1))* calendar.width/2 + calendar.width/2,
// "yEval": Math.cos( 360/(i+1))* calendar.width/2 + calendar.width/2,
// "xEval": ((i % 7)-3.5) * 100+calendar.width/2,
// "yEval": Math.floor(i / 7) * rep.delegateWidth,
"xEval": Math.random()*1000-500,
"yEval": Math.random()*1000-500,
"opacityEval": 0,
"scaleEval": 0.4
});
else
// This 2012 Jan index-2 always return Sunday
listModel.append({
"dayNumberText": Qt.formatDate( new Date(2012, 1, i-2), "ddd" ),
"dayStringText": "",
"grayedCell": true,
"xEval": ((i % 7)-3.5) * 100+calendar.width/2,
"yEval": height/2,
"opacityEval": 0,
"scaleEval": 0.4
});
}
}

Rectangles are also positioned by a random value to get animated while function updateCalendar() will arrange rectangles with their final grid position.

function updateCalendar()
{
var startMonthIndex = new Date(year, month, 1).getDate();
var endMonthIndex = new Date(year, month+1, 0).getDate();
var startWeekIndex = new Date(year, month, startMonthIndex).getDay();
var i;
rep.delegateWidth = Math.min(calendar.width, calendar.height) / 7;
initListModel();
// Set text into days rectangles
for (i=7; i<49; i++) {
var date = new Date(year, month, i-startWeekIndex-6);
rep.model.setProperty(i, "dayNumberText", date.getDate() );
rep.model.setProperty(i, "dayStringText", Qt.formatDate( date, "ddd" ));
if (i-7 >= startWeekIndex && i-7 < startWeekIndex+endMonthIndex)
rep.model.setProperty(i, "grayedCell", false);
}
// Final position of rectangles
for (i=0; i<49; i++) {
rep.model.setProperty(i, "xEval", (i % 7) * rep.delegateWidth );
rep.model.setProperty(i, "yEval", Math.floor(i / 7) * rep.delegateWidth -rep.delegateWidth );
rep.model.setProperty(i, "opacityEval", 1 );
rep.model.setProperty(i, "scaleEval", 1);
}
}


When user click on a day, the rectangles are spread out by function spreadOutRectangles() and the signal dayPicked(variant date) is raised to be caught.

function spreadOutRectangles(itemClicked)
{
for (var i=0; i<49; i++) {
if (i !== itemClicked) {
rep.model.setProperty(i, "xEval", Math.random()*10000-5000);
rep.model.setProperty(i, "yEval", Math.random()*10000-5000);
}
else {
rep.model.setProperty(i, "scaleEval", 5);
}
rep.model.setProperty(i, "opacityEval", 0 );
}
}

We have used the DatePicker component from QML Templates in our project to get year, month or day. Also the signal dayPicked(variant date) is connected with the property date which contains the user choice.

Connections {
target: calendar
onDayPicked: {
console.log( "Date clicked:", Qt.formatDate(date, "ddd dd MMM yyyy"))
dateBar.opacity = 0;
}
}

Summary

This is a basic calendar application, but it shows the usability and flexibility of Qt Quick for creating a fancy UI. The above project talks about the Symbian implementation, but it can also be run on Desktop and MeeGo platforms.

Source Code

The full source code of the example is available here: File:CalendarQML.zip

74 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×