Demo Overview
The clock demo displays a horizontal list of world clocks. Users can drag the list left or right using the mouse. Clocks shown with a dark background indicate nighttime hours (7 PM to 7 AM), while clocks without the dark overlay represent daytime hours.
Source Code Aanlysis
1. Application Entry Point
The main.cpp file contains a single macro for initializing the QML engine. For detailed explanations of this macro, refer to the dedicated article on QML key macros.
2. Clock Component Implementation
The Clock.qml component handles individual clock display and time calculation:
Item {
id: clockItem
// Dynamic width calculation based on parent ListView dimensions
width: {
if (ListView.view && ListView.view.width >= 200)
return ListView.view.width / Math.floor(ListView.view.width / 200.0);
else
return 200;
}
// Dynamic height calculation
height: {
if (ListView.view && ListView.view.height >= 240)
return ListView.view.height;
else
return 240;
}
// Exposed properties for external assignment
property alias cityName: cityText.text
property int hourValue
property int minuteValue
property int secondValue
property real timezoneOffset
property bool isNightTime: false
property bool useUTCTime: true
// Time calculation function
function updateTime() {
var currentDate = new Date;
hourValue = useUTCTime ? currentDate.getUTCHours() + Math.floor(clockItem.timezoneOffset) : currentDate.getHours()
isNightTime = (hourValue < 7 || hourValue > 19)
minuteValue = useUTCTime ? currentDate.getUTCMinutes() + ((clockItem.timezoneOffset % 1) * 60) : currentDate.getMinutes()
secondValue = currentDate.getUTCSeconds();
}
// Periodic timer for real-time updates
Timer {
interval: 100
running: true
repeat: true
onTriggered: clockItem.updateTime()
}
// Clock face container centered in parent
Item {
anchors.centerIn: parent
width: 200
height: 240
// Background images - day vs night variants
Image {
id: dayBackground
source: "clock.png"
visible: clockItem.isNightTime == false
}
Image {
source: "clock-night.png"
visible: clockItem.isNightTime == true
}
// Hour hand
Image {
x: 92.5
y: 27
source: "hour.png"
transform: Rotation {
id: hourHandRotation
origin.x: 7.5
origin.y: 73
angle: (clockItem.hourValue * 30) + (clockItem.minuteValue * 0.5)
Behavior on angle {
SpringAnimation {
spring: 2
damping: 0.2
modulus: 360
}
}
}
}
// Minute hand
Image {
x: 93.5
y: 17
source: "minute.png"
transform: Rotation {
id: minuteHandRotation
origin.x: 6.5
origin.y: 83
angle: clockItem.minuteValue * 6
Behavior on angle {
SpringAnimation {
spring: 2
damping: 0.2
modulus: 360
}
}
}
}
// Second hand
Image {
x: 97.5
y: 20
source: "second.png"
transform: Rotation {
id: secondHandRotation
origin.x: 2.5
origin.y: 80
angle: clockItem.secondValue * 6
Behavior on angle {
SpringAnimation {
spring: 2
damping: 0.2
modulus: 360
}
}
}
}
// Center cap
Image {
anchors.centerIn: dayBackground
source: "center.png"
}
// City name label
Text {
id: cityText
y: 210
anchors.horizontalCenter: parent.horizontalCenter
color: "white"
font.family: "Helvetica"
font.bold: true
font.pixelSize: 16
style: Text.Raised
styleColor: "black"
}
}
}
3. Clock List View
The Clocks.qml file implements a horizontal ListView that displays multiple clock widgets:
import "content" as Widgets
Rectangle {
id: container
width: 640
height: 320
color: "#646464"
// Horizontal scrolling clock list
ListView {
id: clockList
anchors.fill: parent
orientation: ListView.Horizontal
cacheBuffer: 2000
snapMode: ListView.SnapOneItem
highlightRangeMode: ListView.ApplyRange
delegate: Widgets.Clock {
cityName: cityLabel
timezoneOffset: offset
}
// Data model with city names and UTC offsets
model: ListModel {
ListElement { cityLabel: "New York"; offset: -4 }
ListElement { cityLabel: "London"; offset: 0 }
ListElement { cityLabel: "Oslo"; offset: 1 }
ListElement { cityLabel: "Mumbai"; offset: 5.5 }
ListElement { cityLabel: "Tokyo"; offset: 9 }
ListElement { cityLabel: "Brisbane"; offset: 10 }
ListElement { cityLabel: "Los Angeles"; offset: -8 }
}
}
// Left navigation arrow
Image {
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: 10
source: "content/arrow.png"
rotation: -90
opacity: clockList.atXBeginning ? 0 : 0.5
Behavior on opacity {
NumberAnimation { duration: 500 }
}
}
// Right navigation arrow
Image {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 10
source: "content/arrow.png"
rotation: 90
opacity: clockList.atXEnd ? 0 : 0.5
Behavior on opacity {
NumberAnimation { duration: 500 }
}
}
}
Key Implementation Details
- Dynamic Sizing: The clock compoennt calculates its dimensions based on the parent ListView's available space, ensuring proper scaling across different screen sizes.
- Time Zone Support: Each clock accepts a timezone offset property to display time for different global locations using UTC-based calculations.
- Day/Night Detection: The isNightTime property automatically determines whether to display the dark background based on whether the hour value falls outside the 7 AM to 7 PM range.
- Smooth Animations: Spring animasions on the Rotation transforms provide realistic hand movement with natural easing.
- List Navigation: The snapMode and highlightRangeMode properties create a polished user experience when scrolling through the clock list.
- Visual Feedback: Navigation arrows fade in/out based on scroll position using Behavior animations.