summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFurkan Üzümcü <furkanuzumcu@gmail.com>2024-05-13 13:14:45 -0400
committerGitHub <noreply@github.com>2024-05-13 11:14:45 -0600
commit90a16a6d5e317fc58030625945ded8b83f1055b5 (patch)
tree60b6008e198399c9222e9c12fafe4ba85dfd3e2a
parente8d07adad1ce214f89ddfaf623115050ecd45c2b (diff)
[qml/en] Add QML tutorial (#4582)
-rw-r--r--qml.html.markdown368
1 files changed, 368 insertions, 0 deletions
diff --git a/qml.html.markdown b/qml.html.markdown
new file mode 100644
index 00000000..78e94d66
--- /dev/null
+++ b/qml.html.markdown
@@ -0,0 +1,368 @@
+---
+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
+ // type is not avaiable.
+ 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
+ }
+ }
+ }
+ }
+}
+```