The Problem
Every visual aspect of a QML object — its size, color, position, text, opacity — is controlled by properties. You've already used properties like width, color, and text. But properties in QML aren't simple variables. They're reactive: when a property changes, anything bound to it automatically updates.
The Naive Approach
In most programming languages, you set an object's attributes once and they stay fixed:
rect.width = 200
rect.color = "blue"If something changes that should affect those values, you write code to update them. For a desktop shell with constantly changing data (clock, battery, workspace), this means endless manual updates.
Properties in QML are not static assignments — they're like spreadsheet cells. If cell A1 contains =B1 + C1, changing B1 automatically recalculates A1. QML properties work the same way: you can bind one property to an expression involving other properties, and the runtime keeps the result current.
The Idea
A QML property has a name, a type, and a value. Types include basic ones like int, real, string, color, bool, and url, as well as complex types like font and rect. Properties can be:
- Set to a constant value:
width: 200 - Bound to an expression:
width: parent.width * 0.5 - Animated: via
BehaviororAnimationtypes - Custom: declared on your own objects with
property type name
Let's Build It
import QtQuick
import QtQuick.Window
Window {
id: window
width: 400
height: 300
visible: true
title: "Properties"
property string greeting: "Hello!"
property int count: 0
Rectangle {
id: box
x: 50; y: 50
width: 300
height: 100
color: count % 2 === 0 ? "#4ecdc4" : "#ff6b6b"
radius: 8
Text {
text: window.greeting + " Count: " + window.count
anchors.centerIn: parent
color: "white"
font.pixelSize: 18
}
}
Text {
text: "Click the window to increment"
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: 20
color: "#888"
font.pixelSize: 12
}
MouseArea {
anchors.fill: parent
onClicked: {
count = count + 1
}
}
}Click the window. Each click increments count. The rectangle's color expression re-evaluates, flipping between teal and red. The Text inside the box re-reads greeting and count and displays the updated string.
Key property types shown here:
color— accepts named colors ("white","red"), hex codes ("#4ecdc4"), andQt.rgba().- Expression bindings —
color: count % 2 === 0 ? "#4ecdc4" : "#ff6b6b"is not evaluated once. It re-evaluates every timecountchanges. - Custom properties —
property string greeting: "Hello!"andproperty int count: 0are custom properties on theWindow. They're accessible from any child by using the window'sid(in this case,window.greetingandwindow.count).
Let's Improve It
Custom properties can also be read-only:
property int count: 0
readonly property string label: "Clicks: " + countNow label updates automatically when count changes, but you can't assign to label directly — it's computed from count by the binding. Use readonly for properties derived from other state.
Common built-in property types:
Rectangle {
// Basic types
property int integerValue: 42
property real realValue: 3.14
property string textValue: "hello"
property bool booleanValue: true
property color colorValue: "#ff0000"
property url urlValue: "https://example.com"
// Complex types
property variant genericValue: [1, 2, 3]
property font fontValue: Qt.font({ pixelSize: 14, bold: true })
property rect rectValue: Qt.rect(0, 0, 100, 100)
property point pointValue: Qt.point(50, 50)
property size sizeValue: Qt.size(100, 100)
}Under the Hood
Each property in QML is backed by a C++ Q_PROPERTY in the underlying Qt type. When you write color: "#ff6b6b", the QML engine calls QObject::setProperty("color", QColor("#ff6b6b")). For expressions like color: count % 2 === 0 ? "#4ecdc4" : "#ff6b6b", it installs a binding that re-evaluates the expression whenever a dependency changes.
Custom properties declared with property in QML create a new Q_PROPERTY on the fly, complete with a NOTIFY signal that other bindings can depend on.
Using = instead of :. In QML, property assignment uses the colon syntax (property: value), not equals. Using = is a syntax error.
Treating properties as strings when they have specific types. color: "red" works because color accepts a string and converts it. But font.pixelSize: "16" will fail — pixelSize expects an int.
Accessing Window properties from deeply nested children. Use an explicit id on the Window and reference it directly (e.g., window.greeting) rather than relying on parent.parent traversal, which may not work reliably depending on the object hierarchy.
Exercises
- Properties are named, typed attributes that control object appearance and behavior
- Expression bindings re-evaluate automatically when dependencies change
- Custom properties declared with property are accessible throughout the object hierarchy
- Use explicit ids to reference parent or ancestor properties reliably