learnxinyminutes-docs/qml.md

369 lines
11 KiB
Markdown
Raw Normal View History

2024-05-13 17:14:45 +00:00
---
language: QML
contributors:
- ["Furkan Uzumcu", "https://zmc.space/"]
filename: learnqml.qml
lang: en-us
---
```qml
// This is a completely valid QML file that you can run using `qmlscene` if you copy the contents
// into a *.qml file.
// Comments start with double forward slashes.
/* Or you
can have
multi line
comments
*/
// Import statement syntax is
// import ${MODULE_NAME} [${VERSION_NUMBER}] [as ${QUALIFIER}]
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QQC
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1
// Each QML document can contain only one top level type
Window {
// Each object has a special and optional `id` attribute that can be used to refer to the
// declared objects. An `id` has to be unique in the same document.
id: root
width: 400
height: 600
title: "Learn QML in Y Minutes"
Item {
// Every object that can be declared inherits from QObject and contains at
// least one property, which is `objectName`. All the other properties are
// added by extending `QObject` type. This is an `Item` type and it contains
// the additional `width` and `height` properties and more.
objectName: "My Item"
// `id`s in the same document can be used anywhere in the same file.
// You cannot access an `id` from a different file.
width: root.width
}
// Signals are used to communicate that a certain event happened.
// Some types have built-in signals
Timer {
id: timer
interval: 500
onTriggered: {
console.log("Timer triggered!")
}
}
QtObject {
id: objSignals
// You can also declare your own signals.
signal clicked()
// Signals can also have arguments.
signal mousePositionChanged(int x, int y)
// The way to react to a signal emission is by adding signal handlers to
// the immediate object that the signal belongs to.
onClicked: () => {
// Do stuff here.
console.log("objSignals.clicked() signal is emitted.")
}
// Signal handlers must explicitly declare the arguments.
onMousePositionChanged: (x, y) => {
// Do stuff here.
console.log("objSignals.mousePositionChanged() signal is emitted. x=", x, "y=", y)
}
}
// If you want to declare signal handlers for other objects, you can use
// `Connections`.
Connections {
target: objSignals
// You can then declare functions with the same name as the signal
// handler.
function onClicked() {
console.log("objSignals.clicked() signal is handled from Connections.")
}
}
Item {
visible: false
// An object can support having child objects. You can add child objects
// by declaring types as follows:
Rectangle {
width: 16
height: 16
color: "red"
}
}
Item {
id: objProperties
// You can also declare your own properties.
// Syntax for declaring is
// [default] [required] [readonly] property ${TYPE} ${NAME}
property color nextColor
// Read only properties have to be initialized when declared.
readonly property color defaultColor: "red"
// Required properties have to be initialized where the reusable type is
// used.
required property color initialColor
// NOTE: Although the initial assignment can be done in the same file,
// it is not often the use case.
initialColor: "green"
// Properties are type safe and a property can only be assigned a value
// that matches the property type.
// property int volume: "four" // ERROR!
Item {
// You can create alias properties that hold a reference to another
// property.
property alias parentNextColor: objProperties.nextColor
// Assignments to alias properties alter the property that it holds
// a reference to.
parentNextColor: "blue" // Changes objProperties.nextColor
// Since `parentNextColor` is an alias to `nextColor`, any changes
// to `nextColor` will also be reflected to `parentNextColor`.
}
}
Item {
// Property assignment values can either be static or binding
// expressions.
// Static value
property int radius: 32
// Binding expressions describe a property's relationship to other
// properties. When the value of `radius` changes, the expression here
// will be re-evaluated.
property int diameter: radius * 2
onDiameterChanged: {
console.log("onDiameterChanged:", diameter)
}
}
ListView {
// Attached properties and signal handlers provide a way to extend an
// existing object and provide more information that is otherwise not
// immediately available.
width: 100
height: 30
model: 3
delegate: Rectangle {
// ListView provides an attached property for its children that can
// be used to access more information.
color: ListView.isCurrentItem ? "green" : "red"
}
// Attached types can also have signal handlers.
// `Component` is attached to every type that's available in QML.
Component.onCompleted: {
console.log("This signal handler is called after object is created.")
}
}
Rectangle {
// Since this rectangle is not created by the ListView, the attached
2024-08-28 14:17:15 +00:00
// type is not available.
2024-05-13 17:14:45 +00:00
color: ListView.isCurrentItem ? "green" : "red"
}
QtObject {
id: calculator
// Objects can also declare methods. Function declarations can annotate
// the arguments, or have no arguments at all.
function add(a: int, b: int): int {
// Semicolon at the end of a line is optional.
return a + b
}
function multiply(a: real, b: real): real {
return a * b;
}
}
MouseArea {
anchors.fill: parent
onClicked: (mouse) => {
console.log("2 + 2 =", calculator.add(2, 2))
}
}
Item {
width: 100
// Methods can also be used as binding expressions. When `width`
// changes, the binding expression will evaluate and call `multiply`.
height: calculator.multiply(width, 0.5)
opacity: calculateOpacity()
function calculateOpacity() {
// If the function declaration contains references to other
// properties, changes to those properties also trigger a binding
// evaluation.
return height < 50 ? 0.5 : 1
}
}
// Each QML file that starts with an upper case name declares a re-usable
// component, e.g "RedRectangle.qml".
// In addition, reusable components can be declared in-line.
component RedRectangle: Rectangle {
color: "red"
}
// This inline component can then be used in the same file, or in other
// files by prefixing the type name with the file name that it belongs to.
//
// ${FILE_NAME}.RedRectangle { }
// or
RedRectangle {
}
// QML also supports enumeration declarations.
component MyText: Text {
enum TextType {
Normal,
Heading
}
// Enum types are assigned to integer properties.
property int textType: MyText.TextType.Normal
font.bold: textType == MyText.TextType.Heading
font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
}
// ----- Interactive Area
QQC.ScrollView {
anchors.fill: parent
contentWidth: container.implicitWidth
contentHeight: container.implicitHeight
Column {
id: container
spacing: 6
Row {
spacing: 2
QQC.Label {
width: 200
anchors.verticalCenter: parent.verticalCenter
text: "Click to start the timer.\nCheck the logs!"
wrapMode: QQC.Label.WordWrap
}
QQC.Button {
text: timer.running ? "Timer Running" : "Start Timer"
onClicked: {
timer.start()
}
}
}
Row {
spacing: 2
QQC.Label {
width: 200
anchors.verticalCenter: parent.verticalCenter
text: "Click to emit objSignals.clicked() signal"
wrapMode: QQC.Label.WordWrap
}
QQC.Button {
property int emissionCount: 0
text: "Emitted " + emissionCount + " times."
onClicked: {
objSignals.clicked()
emissionCount++
}
}
}
Row {
spacing: 2
QQC.Label {
width: 200
anchors.verticalCenter: parent.verticalCenter
text: "Click to emit objSignals.mousePositionChanged() signal"
wrapMode: QQC.Label.WordWrap
}
QQC.Button {
property int emissionCount: 0
text: "Emitted " + emissionCount + " times."
onClicked: {
objSignals.mousePositionChanged(32, 32)
emissionCount++
}
}
}
Rectangle {
width: 200
height: 80
color: objProperties.nextColor
QQC.Label {
width: 200
anchors.verticalCenter: parent.verticalCenter
text: "Click to change nextColor property."
wrapMode: QQC.Label.WordWrap
}
TapHandler {
onTapped: {
colorDialog.open()
}
}
ColorDialog {
id: colorDialog
currentColor: objProperties.initialColor
onColorChanged: {
objProperties.nextColor = color
}
}
}
Row {
spacing: 2
Rectangle {
width: 200
height: 80
color: "red"
radius: radiusSlider.value
QQC.Label {
width: parent.width
anchors.centerIn: parent
text: "Use slider to change radius"
wrapMode: QQC.Label.WordWrap
horizontalAlignment: Qt.AlignHCenter
}
}
QQC.Slider {
id: radiusSlider
width: 100
anchors.verticalCenter: parent.verticalCenter
from: 0
to: 80
}
}
}
}
}
```