feat: add QML overview
This commit is contained in:
parent
1ca13d9ffd
commit
adead138b0
|
@ -45,3 +45,7 @@
|
||||||
.qmlprops {
|
.qmlprops {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
|
@ -5,5 +5,6 @@
|
||||||
Quickshell is a fully user customizable desktop shell based on QtQuick.
|
Quickshell is a fully user customizable desktop shell based on QtQuick.
|
||||||
|
|
||||||
{{< cards >}}
|
{{< cards >}}
|
||||||
|
{{< card link="/docs/configuration" title="Configuration" >}}
|
||||||
{{< card link="/docs/types" title="Type Reference" >}}
|
{{< card link="/docs/types" title="Type Reference" >}}
|
||||||
{{< /cards >}}
|
{{< /cards >}}
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
+++
|
+++
|
||||||
title = 'Docs'
|
title = 'Docs'
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
{{< cards >}}
|
||||||
|
{{< card link="./configuration" title="Configuration" >}}
|
||||||
|
{{< card link="./types" title="Type Reference" >}}
|
||||||
|
{{< /cards >}}
|
||||||
|
|
7
content/docs/configuration/_index.md
Normal file
7
content/docs/configuration/_index.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
+++
|
||||||
|
title = "Configuration"
|
||||||
|
+++
|
||||||
|
|
||||||
|
We recommend you read the [QML Overview](./qml-overview) to get started,
|
||||||
|
then check out the [Type Reference](/docs/types) to find the types you have
|
||||||
|
to work with.
|
764
content/docs/configuration/qml-overview.md
Normal file
764
content/docs/configuration/qml-overview.md
Normal file
|
@ -0,0 +1,764 @@
|
||||||
|
+++
|
||||||
|
title = "QML Overview"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Quickshell is configured using the Qt Modeling Language, or QML.
|
||||||
|
This page explains what you need to know about QML to start using quickshell.
|
||||||
|
|
||||||
|
<span class="small">See also: [Qt Documentation: QML Tutorial](https://doc.qt.io/qt-6/qml-tutorial.html)</span>
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
Below is a QML document showing most of the syntax.
|
||||||
|
Keep it in mind as you read the detailed descriptions below.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Semicolons are permitted basically everywhere, and recommended in
|
||||||
|
functions and expressions.
|
||||||
|
- While types can often be elided, we recommend you use them where
|
||||||
|
possible to catch proplems early instead of running into them unexpectedly layer on.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
// QML Import statement
|
||||||
|
import QtQuick 6.0
|
||||||
|
|
||||||
|
// Javascript import statement
|
||||||
|
import "myjs.js" as MyJs
|
||||||
|
|
||||||
|
// Root Object
|
||||||
|
Item {
|
||||||
|
// Id assignment
|
||||||
|
|
||||||
|
id: root
|
||||||
|
// Property declaration
|
||||||
|
property int myProp: 5;
|
||||||
|
|
||||||
|
// Property binding
|
||||||
|
width: 100
|
||||||
|
|
||||||
|
// Property binding
|
||||||
|
height: width
|
||||||
|
|
||||||
|
// Multiline property binding
|
||||||
|
prop: {
|
||||||
|
// ...
|
||||||
|
5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object assigned to a property
|
||||||
|
objProp: Object {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object assigned to the parent's default property
|
||||||
|
AnotherObject {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal declaration
|
||||||
|
signal foo(bar: int)
|
||||||
|
|
||||||
|
// Signal handler
|
||||||
|
onSignal: console.log("received signal!")
|
||||||
|
|
||||||
|
// Property change signal handler
|
||||||
|
onWidthChanged: console.log(`width is now ${width}!`)
|
||||||
|
|
||||||
|
// Multiline signal handler
|
||||||
|
onOtherSignal: {
|
||||||
|
console.log("received other signal!");
|
||||||
|
console.log(`5 * 2 is ${dub(5)}`);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attached property signal handler
|
||||||
|
Component.onCompleted: MyJs.myfunction()
|
||||||
|
|
||||||
|
// Function
|
||||||
|
function dub(x: int): int {
|
||||||
|
return x * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Imports
|
||||||
|
|
||||||
|
#### Explicit imports
|
||||||
|
Every QML File begins with a list of imports.
|
||||||
|
Import statements tell the QML engine where
|
||||||
|
to look for types you can create [objects](#objects) from.
|
||||||
|
|
||||||
|
A module import statement looks like this:
|
||||||
|
```qml
|
||||||
|
import <Module> [Major.Minor] [as <Namespace>]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `Module` is the name of the module you want to import, such as `QtQuick`.
|
||||||
|
- `Major.Minor` is the version of the module you want to import.
|
||||||
|
- `Namespace` is an optional namespace to import types from the module under.
|
||||||
|
|
||||||
|
A subfolder import statement looks like this:
|
||||||
|
```qml
|
||||||
|
import "<directory>" [as <Namespace>]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `directory` is the directory to import, relative to the current file.
|
||||||
|
- `Namespace` is an optional namespace to import types from the folder under.
|
||||||
|
|
||||||
|
A javascript import statement looks like this:
|
||||||
|
```qml
|
||||||
|
import "<filename>" as <Namespace>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `filename` is the name of the javascript file to import.
|
||||||
|
- `Namespace` is the namespace functions and variables from the javascript
|
||||||
|
file will be made available under.
|
||||||
|
|
||||||
|
Note: All *Module* and *Namespace* names must start with an uppercase letter.
|
||||||
|
Attempting to use a lowercase namespace is an error.
|
||||||
|
|
||||||
|
##### Examples
|
||||||
|
```qml
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls 6.0
|
||||||
|
import Quickshell as QS
|
||||||
|
import QtQuick.Layouts 6.0 as L
|
||||||
|
import "jsfile.js" as JsFile
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% details title="When to use versions" closed="true" %}}
|
||||||
|
|
||||||
|
By default, when no module version is requested, the QML engine will pick
|
||||||
|
the latest available version of the module. Requesting a specific version
|
||||||
|
can help ensure you get a specific version of the module's types, and as a
|
||||||
|
result your code dosen't break across Qt or quickshell updates.
|
||||||
|
|
||||||
|
While Qt's types usually don't majorly change across versions, quickshell's
|
||||||
|
are much more likely to break. To put off dealing with the breakage we suggest
|
||||||
|
specifying a version at least when importing quickshell modules.
|
||||||
|
|
||||||
|
{{% /details %}}
|
||||||
|
|
||||||
|
<span class="small">[Qt Documentation: Import syntax](https://doc.qt.io/qt-6/qtqml-syntax-imports.html)</span>
|
||||||
|
|
||||||
|
#### Implicit imports
|
||||||
|
|
||||||
|
The QML engine will automatically import any [types](#types) in neighboring files
|
||||||
|
with names that start with an uppercase letter.
|
||||||
|
|
||||||
|
```
|
||||||
|
root
|
||||||
|
|-MyButton.qml
|
||||||
|
|-shell.qml
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, `MyButton` will automatically be imported as a type usable from shell.qml
|
||||||
|
or any other neighboring files.
|
||||||
|
|
||||||
|
### Objects
|
||||||
|
|
||||||
|
Objects are instances of a type from an imported module.
|
||||||
|
The name of an object must start with an uppercase letter.
|
||||||
|
This will always distinguish an object from a property.
|
||||||
|
|
||||||
|
An object looks like this:
|
||||||
|
```qml
|
||||||
|
Name {
|
||||||
|
id: foo
|
||||||
|
// properties, functions, signals, etc...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Every object can contain [properties](#properties), [functions](#functions),
|
||||||
|
and [signals](#signals). You can find out what properties are available for a type
|
||||||
|
by looking it up in the [Type Reference](/docs/types/).
|
||||||
|
|
||||||
|
#### Properties
|
||||||
|
|
||||||
|
Every object may have any number of property assignments (only one per specific property).
|
||||||
|
Each assignment binds the named property to the given expression.
|
||||||
|
|
||||||
|
##### Property bindings
|
||||||
|
|
||||||
|
Expressions are snippets of javascript code assigned to a property. The last (or only) line
|
||||||
|
can be the return value, or an explicit return statement (multiline expressions only) can be used.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
// simple expression
|
||||||
|
property: 5
|
||||||
|
|
||||||
|
// complex expression
|
||||||
|
property: 5 * 20 + this.otherProperty
|
||||||
|
|
||||||
|
// multiline expression
|
||||||
|
property: {
|
||||||
|
const foo = 5;
|
||||||
|
const bar = 10;
|
||||||
|
foo * bar
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiline expression with return
|
||||||
|
property: {
|
||||||
|
// ...
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Semicolons are optional and allowed on any line of a single or multiline expression,
|
||||||
|
including the last line.
|
||||||
|
|
||||||
|
All property bindings are [*reactive*](#reactive-bindings), which means when any property the expression depends
|
||||||
|
on is updated, the expression is re-evaluated and the property is updated.
|
||||||
|
|
||||||
|
<span class="small">See: [Reactive bindings](#reactive-bindings)</span>
|
||||||
|
|
||||||
|
Note that it is an error to try to assign to a property that does not exist.
|
||||||
|
(See: [property definitions](#property-definitions))
|
||||||
|
|
||||||
|
##### Property definitions
|
||||||
|
|
||||||
|
Properties can be defined inside of objects with the following syntax:
|
||||||
|
```qml
|
||||||
|
[required] [readonly] [default] property <type> <name>[: binding]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `required` forces users of this type to assign this property. See [Types](#types) for details.
|
||||||
|
- `readonly` makes the property not assignable. Its binding will still be [reactive](#reactive-bindings).
|
||||||
|
- `default` makes the property the default property of this type. See [Types](#types)
|
||||||
|
for details.
|
||||||
|
- `type` is the type of the property. You can use `var` if you don't know or don't care but be aware that `var` will
|
||||||
|
allow any value type.
|
||||||
|
- `name` is the name that the property is known as. It cannot start with an uppercase letter.
|
||||||
|
- `binding` is the property binding. See [Property bindings](#property-bindings) for details.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
// normal property
|
||||||
|
property int foo: 3
|
||||||
|
|
||||||
|
// readonly property
|
||||||
|
readonly property string bar: "hi!"
|
||||||
|
|
||||||
|
// bound property
|
||||||
|
property var things: [ "foo", "bar" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Defining a property with the same name as one provided by the current object will override
|
||||||
|
the property of the type it is derived from in the current context.
|
||||||
|
|
||||||
|
##### The `id` property
|
||||||
|
|
||||||
|
Every object has a special property called `id` that can be assigned to give
|
||||||
|
the object a name it can be referred to throughout the current file. The id must be lowercase.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
text: "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Make the text red";
|
||||||
|
onClicked: text.color = "red";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% details title="The `id` property compared to normal properties" closed="true" %}}
|
||||||
|
|
||||||
|
The `id` property isn't really a property, and dosen't do anything other than
|
||||||
|
expose the object to the current file. It is only called a property because it
|
||||||
|
uses very similar syntax to one, and is the only exception to standard property
|
||||||
|
definition rules. The name `id` is always reserved for the id property.
|
||||||
|
|
||||||
|
{{% /details %}}
|
||||||
|
|
||||||
|
##### Property access scopes
|
||||||
|
|
||||||
|
Properties are "in scope" and usable in two cases.
|
||||||
|
1. They are defined for current type.
|
||||||
|
2. They are defined for the root type in the current file.
|
||||||
|
|
||||||
|
You can access the properties of any object by setting its [id property](#the-id-property),
|
||||||
|
or make sure the property you are accessing is from the current object using `this`.
|
||||||
|
|
||||||
|
The `parent` property is also defined for all objects, but may not always point to what it
|
||||||
|
looks like it should. Use the `id` property if `parent` does not do what you want.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
property string rootDefinition
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: mid
|
||||||
|
property string midDefinition
|
||||||
|
|
||||||
|
Text {
|
||||||
|
property string innerDefinition
|
||||||
|
|
||||||
|
// legal - innerDefinition is defined on the current object
|
||||||
|
text: innerDefinition
|
||||||
|
|
||||||
|
// legal - innerDefinition is accessed via `this` to refer to the current object
|
||||||
|
text: this.innerDefinition
|
||||||
|
|
||||||
|
// legal - width is defined for Text
|
||||||
|
text: width
|
||||||
|
|
||||||
|
// legal - rootDefinition is defined on the root object
|
||||||
|
text: rootDefinition
|
||||||
|
|
||||||
|
// illegal - midDefinition is not defined on the root or current object
|
||||||
|
text: midDefinition
|
||||||
|
|
||||||
|
// legal - midDefinition is accessed via `mid`'s id.
|
||||||
|
text: mid.midDefinition
|
||||||
|
|
||||||
|
// legal - midDefinition is accessed via `parent`
|
||||||
|
text: parent.midDefinition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<span class="small">[Qt Documentation: Scope and Naming Resolution](https://doc.qt.io/qt-6/qtqml-documents-scope.html)</span>
|
||||||
|
|
||||||
|
#### Functions
|
||||||
|
|
||||||
|
Functions in QML can be declared everywhere [properties](#properties) can, and follow
|
||||||
|
the same [scoping rules](#property-access-scopes).
|
||||||
|
|
||||||
|
Function definition syntax:
|
||||||
|
```qml
|
||||||
|
function <name>(<paramname>[: <type>][, ...])[: returntype] {
|
||||||
|
// multiline expression (note that `return` is required)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Functions can be invoked in expressions. Expression reactivity carries through
|
||||||
|
functions, meaning if one of the properties a function depends on is re-evaluated,
|
||||||
|
every expression depending on the function is also re-evaluated.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
property int clicks: 0
|
||||||
|
|
||||||
|
function makeClicksLabel(): string {
|
||||||
|
return "the button has been clicked " + clicks + " times!";
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "click me"
|
||||||
|
onClicked: clicks += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: makeClicksLabel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, every time the button is clicked, the label's count increases
|
||||||
|
by one, as `clicks` is changed, which triggers a re-evaluation of `text` through
|
||||||
|
`makeClicksLabel`.
|
||||||
|
|
||||||
|
##### Lambdas
|
||||||
|
|
||||||
|
Functions can also be values, and you can assign them to properties or pass them to
|
||||||
|
other functions (callbacks). There is a shorter way to write these functions, known
|
||||||
|
as lambdas.
|
||||||
|
|
||||||
|
Lambda syntax:
|
||||||
|
```qml
|
||||||
|
<params> => <expression>
|
||||||
|
|
||||||
|
// params can take the following forms:
|
||||||
|
() => ... // 0 parameters
|
||||||
|
<name> => ... // 1 parameter
|
||||||
|
(<name>[, ...]) => ... // 1+ parameters
|
||||||
|
|
||||||
|
// the expression can be either a single or multiline expression.
|
||||||
|
... => <result>
|
||||||
|
... => {
|
||||||
|
return <result>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Assigning functions to properties:
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
// using functions
|
||||||
|
function dub(number: int): int { return number * 2; }
|
||||||
|
property var operation: dub
|
||||||
|
|
||||||
|
// using lambdas
|
||||||
|
property var operation: number => number * 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
An overcomplicated click counter using a lambda callback:
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
property int clicks: 0
|
||||||
|
|
||||||
|
function incrementAndCall(callback) {
|
||||||
|
clicks += 1;
|
||||||
|
callback(clicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "click me"
|
||||||
|
onClicked: incrementAndCall(clicks => {
|
||||||
|
label.text = `the button was clicked ${clicks} time(s)!`;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: "the button has not been clicked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Signals
|
||||||
|
A signal is basically an event emitter you can connect to and receive updates from.
|
||||||
|
They can be declared everywhere [properties](#properties) and [functions](#functions)
|
||||||
|
can, and follow the same [scoping rules](#property-access-scopes).
|
||||||
|
|
||||||
|
<span class="small">[Qt Documentation: Signal and Handler Event System](https://doc.qt.io/qt-6/qtqml-syntax-signals.html)</span>
|
||||||
|
|
||||||
|
##### Signal definitions
|
||||||
|
|
||||||
|
A signal can be explicitly defined with the following syntax:
|
||||||
|
```qml
|
||||||
|
signal <name>(<paramname>: <type>[, ...])
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Making connections
|
||||||
|
Signals all have a `connect(<function>)` method which invokes the given function
|
||||||
|
or signal when the signal is emitted.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
property int clicks: 0
|
||||||
|
|
||||||
|
function updateText() {
|
||||||
|
clicks += 1;
|
||||||
|
label.text = `the button has been clicked ${clicks} times!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: button
|
||||||
|
text: "click me"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: "the button has not been clicked"
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
button.clicked.connect(updateText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<span class="small">`Component.onCompleted` will be addressed later
|
||||||
|
in [Attached Properties](#attached-properties) but for now just know that
|
||||||
|
it runs immediately once the object is fully initialized.</span>
|
||||||
|
|
||||||
|
When the button is clicked, the button emits the `clicked` signal which we connected to
|
||||||
|
`updateText`. The signal then invokes `updateText` which updates the counter and the
|
||||||
|
text on the label.
|
||||||
|
|
||||||
|
##### Signal handlers
|
||||||
|
Signal handlers are a more concise way to make a connections, and prior examples have used them.
|
||||||
|
|
||||||
|
When creating an object, for every signal present on its type there is a corrosponding `on<Signal>`
|
||||||
|
property implicitly defined which can be set to a function. (Note that the first letter of the
|
||||||
|
signal's name it capitalized.)
|
||||||
|
|
||||||
|
Below is the same example as in [Making Connections](#making-connections),
|
||||||
|
this time using the implicit signal handler property to handle `button.clicked`.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
property int clicks: 0
|
||||||
|
|
||||||
|
function updateText() {
|
||||||
|
clicks += 1;
|
||||||
|
label.text = `the button has been clicked ${clicks} times!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "click me"
|
||||||
|
onClicked: updateText()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: "the button has not been clicked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Property change signals
|
||||||
|
Every property has an associated signal, which powers QML's [reactive bindings](#reactive-bindings).
|
||||||
|
The signal is named `<propertyname>Changed` and works exactly the same as any other signal.
|
||||||
|
|
||||||
|
Whenever the property is re-evaluated, its change signal is emitted. This is used internally
|
||||||
|
to update dependent properties, but can be directly used, usually with a signal handler.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: "check me"
|
||||||
|
|
||||||
|
onCheckStateChanged: {
|
||||||
|
label.text = labelText(checkState == Qt.Checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: labelText(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function labelText(checked): string {
|
||||||
|
return `the checkbox is checked: ${checked}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example we listen for the `checkState` property of the CheckBox changing
|
||||||
|
using its change signal, `checkStateChanged` with the signal handler `onCheckStateChanged`.
|
||||||
|
|
||||||
|
Since text is also a property we can do the same thing more concisely:
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
id: checkbox
|
||||||
|
text: "check me"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: labelText(checkbox.checkState == Qt.Checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
function labelText(checked): string {
|
||||||
|
return `the checkbox is checked: ${checked}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And the function can also be inlined to an expression:
|
||||||
|
```qml
|
||||||
|
ColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
id: checkbox
|
||||||
|
text: "check me"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
text: {
|
||||||
|
const checked = checkbox.checkState == Qt.Checked;
|
||||||
|
return `the checkbox is checked: ${checked}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also remove the return statement if you wish.
|
||||||
|
|
||||||
|
##### Attached objects
|
||||||
|
|
||||||
|
Attached objects are additional objects that can be associated with an object
|
||||||
|
as decided by internal library code. The documentation for a type will
|
||||||
|
tell you if it can be used as an attached object and how.
|
||||||
|
|
||||||
|
Attached objects are acccessed in the form `<Typename>.<member>` and can have
|
||||||
|
properties, functions and signals.
|
||||||
|
|
||||||
|
A good example is the [Component](https://doc.qt.io/qt-6/qml-qtqml-component.html) type,
|
||||||
|
which is attached to every object and often used to run code when an object initializes.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Text {
|
||||||
|
Component.onCompleted: {
|
||||||
|
text = "hello!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, the text property is set inside the `Component.onCompleted` attached signal handler.
|
||||||
|
|
||||||
|
#### Creating types
|
||||||
|
|
||||||
|
Every QML file with an uppercase name is implicitly a type, and can be used from
|
||||||
|
neighboring files or imported (See [Imports](#imports).)
|
||||||
|
|
||||||
|
A type definition is just a normal object. All properties defined for the root object
|
||||||
|
are visible to the consumer of the type. Objects identified by [id properties](#the-id-property)
|
||||||
|
are not visible outside the file.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
// MyText.qml
|
||||||
|
Rectangle {
|
||||||
|
required property string text
|
||||||
|
|
||||||
|
color: "red"
|
||||||
|
implicitWidth: textObj.implicitWidth
|
||||||
|
implicitHeight: textObj.implicitHeight
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: textObj
|
||||||
|
anchors.fill: parent
|
||||||
|
text: parent.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnotherComponent.qml
|
||||||
|
Item {
|
||||||
|
MyText {
|
||||||
|
// The `text` property of `MyText` is required, so we must set it.
|
||||||
|
text: "Hello World!"
|
||||||
|
|
||||||
|
// `anchors` is a property of `Item` which `Rectangle` subclasses,
|
||||||
|
// so it is available on MyText.
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
// `color` is a property of `Rectangle`. Even though MyText sets it
|
||||||
|
// to "red", we can override it here.
|
||||||
|
color: "blue"
|
||||||
|
|
||||||
|
// `textObj` is has an `id` within MyText.qml but is not a property
|
||||||
|
// so we cannot access it.
|
||||||
|
textObj.color: "red" // illegal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Concepts
|
||||||
|
|
||||||
|
### Reactive bindings
|
||||||
|
<span class="small">This section assumes knowledge of:
|
||||||
|
[Properties](#properties), [Signals](#signals), and [Functions](#functions).
|
||||||
|
See also the [Qt documentation](https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html).
|
||||||
|
</span>
|
||||||
|
|
||||||
|
Reactivity is when a property is updated based on updates to another property.
|
||||||
|
Every time one of the properties in a binding change, the binding is re-evaluated
|
||||||
|
and the bound property takes the new result. Any bindings that depend on that property
|
||||||
|
are then re-evaluated and so forth.
|
||||||
|
|
||||||
|
Bindings can be created in two different ways:
|
||||||
|
|
||||||
|
##### Automatic bindings
|
||||||
|
A reactive binding occurs automatically when you use one or more properties in the definition
|
||||||
|
of another property. .
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
property int clicks: 0
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: `clicks: ${clicks}`
|
||||||
|
onClicked: clicks += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, the button's `text` property is re-evaluated every time the button is clicked, because
|
||||||
|
the `clicks` property has changed.
|
||||||
|
|
||||||
|
###### Avoiding creation
|
||||||
|
To avoid creating a binding, do not use any other properties in the definition of a property.
|
||||||
|
|
||||||
|
You can use the `Component.onCompleted` signal to set a value using a property without creating a binding,
|
||||||
|
as assignments to properties do not create binding.
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
property string theProperty: "initial value"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
// text: "Right now, theProperty is: " + theProperty
|
||||||
|
Component.onCompleted: text = "At creation time, theProperty is: " + theProperty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Manual bindings
|
||||||
|
Sometimes (not often) you need to create a binding inside of a function, signal, or expression.
|
||||||
|
If you need to change or attach a binding at runtime, the `Qt.binding` function can be used to
|
||||||
|
create one.
|
||||||
|
|
||||||
|
The `Qt.binding` function takes another function as an argument, and when assigned to a property,
|
||||||
|
the property will use that function as its binding expression.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
Text {
|
||||||
|
id: boundText
|
||||||
|
text: "not bound to anything"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "bind the above text"
|
||||||
|
onClicked: {
|
||||||
|
if (boundText.text == "not bound to anything") {
|
||||||
|
text = "press me";
|
||||||
|
boundText.text = Qt.binding(() => `button is pressed: ${this.pressed}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, `boundText`'s `text` property is bound to the button's pressed state
|
||||||
|
when the button is first clicked. When you press or unpress the button the text will
|
||||||
|
be updated.
|
||||||
|
|
||||||
|
##### Removing bindings
|
||||||
|
To remove a binding, just assign a new value to the property without using `Qt.binding`.
|
||||||
|
|
||||||
|
```qml
|
||||||
|
Item {
|
||||||
|
Text {
|
||||||
|
id: boundText
|
||||||
|
text: `button is pressed: ${theButton.pressed}`
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: theButton
|
||||||
|
text: "break the binding"
|
||||||
|
onClicked: boundText.text = `button was pressed at the time the binding was broken: ${pressed}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When the button is first pressed, the text will be updated, but once `onClicked` fires
|
||||||
|
the text will be unbound, and even though it contains a reference to the `pressed` property,
|
||||||
|
it will not be updated further by the binding.
|
||||||
|
|
||||||
|
### Lazy loading
|
||||||
|
|
||||||
|
Often not all of your interface needs to load immediately. By default the QML
|
||||||
|
engine initializes every object in the scene before showing anything onscreen.
|
||||||
|
For parts of the interface you don't need to load immediately, you should
|
||||||
|
load them lazily to make your interface load faster.
|
||||||
|
|
||||||
|
The [Loader](https://doc.qt.io/qt-6/qml-qtquick-loader.html) type can help with
|
||||||
|
this, by loading in external files or creating components at runtime. Check its
|
||||||
|
documentation for more information.
|
||||||
|
|
||||||
|
#### Components
|
||||||
|
|
||||||
|
Another delayed loading mechanism is the [Component](https://doc.qt.io/qt-6/qml-qtqml-component.html) type.
|
||||||
|
This type can be used to create multiple instances of objects or lazily load them. It's used by types such
|
||||||
|
as [Repeater](https://doc.qt.io/qt-6/qml-qtquick-repeater.html)
|
||||||
|
and [Quickshell.Variants](/docs/types/quickshell/variants)
|
||||||
|
to create instances of a component at runtime.
|
Loading…
Reference in a new issue