// CircleMouseArea.qml
Item {
id: root
property int radius
signal clicked(MouseEvent mouse)
implicitWidth: 50
implicitHeight: 50
Rectangle {
width: parent.width / 2
height: height
radius: root.radius
}
MouseArea {
// If mouse click is inside the circle, emits root.clicked(mouse)
}
}
QtObject
for encapsulating private members[1]// CustomMouseArea.qml
MouseArea {
Component.onCompleted: { }
onTripleClicked: { }
onClicked: { }
pressAndHoldInterval: 20
signal tripleClicked()
property point pressedPosition
id: root
}
// CustomMouseArea.qml
MouseArea {
id: root
property point pressedPosition
signal tripleClicked()
pressAndHoldInterval: 20
onClicked: { }
onTripleClicked: { }
Component.onCompleted: { }
Component.onDestruction: { }
}
Item {
Item {
anchors.left: parent.left
z: 32
x: 23
y: 32
implicitWidth: 300
width: 300
id: myItem
}
}
Item {
Item {
id: myItem
x: 23
y: 32
z: 32
implicitWidth: 300
width: 300
anchors.left: parent.left
}
}
Item {
id: root
function someFunction() { }
someProperty: true
}
Item {
id: root
someProperty: true
// Function are declared at the bottom of the document.
function someFunction() { }
}
RowLayout {
Item {
states: [ State { } ]
transitions: [ Transitions { } ]
width: 300
Layout.fillHeight: true
enabled: true
layer.enabled: false
}
}
RowLayout {
Item {
width: 300
enabled: true
layer.enabled: false
Layout.fillHeight: true
states: [ State { } ]
transitions: [ Transitions { } ]
}
}
// First Qt imports
import QtQuick 2.15
import QtQuick.Controls 2.15
// Then custom imports
import my.library 1.0
Item {
id: root
// ----- Property Declarations
// Required properties should be at the top.
required property int radius: 0
property int radius: 0
property color borderColor: "blue"
// ----- Signal declarations
signal clicked()
signal doubleClicked()
// ----- In this section, we group the size and position information together.
x: 0
y: 0
z: 0
width: 100
height: 100
anchors.top: parent.top // If a single assignment, dot notation can be used.
// If the item is an image, sourceSize is also set here.
// sourceSize: Qt.size(12, 12)
// ----- Then comes the other properties. There's no predefined order to these.
// Do not use empty lines to separate the assignments. Empty lines are reserved
// for separating type declarations.
enabled: true
layer.enabled: true
// ----- Then attached properties and attached signal handlers.
Layout.fillWidth: true
Drag.active: false
Drag.onActiveChanged: { }
// ----- States and transitions.
states: [ State { } ]
transitions: [ Transitions { } ]
// ----- Signal handlers
onWidthChanged: { } // Always use curly braces.
// onCompleted and onDestruction signal handlers are always the last in
// the order.
Component.onCompleted: { }
Component.onDestruction: { }
// ----- Visual children.
Rectangle {
height: 50
anchors: { // For multiple assignments, use group notation.
top: parent.top
left: parent.left
right: parent.right
}
color: "red"
layer.enabled: true
}
// ----- Qt provided non-visual children
Timer { }
// ----- Custom non-visual children
MyCustomNonVisualType { }
QtObject {
id: privates
property int diameter: 0
}
// ----- JavaScript functions
function collapse() { }
function setCollapsed(value: bool) { }
}
Declarative > Imperative
ListView {
model: ContactModel { }
delegate: Label {
id: dlg
required property int index
required property string name
// Or onIndexChanged? onNameChanged?
Component.onCompleted: {
text = index + ". " + name
rect.visible = dlg.index % 2
}
Rectangle {
id: rect
}
}
}
ListView {
model: ContactModel { }
delegate: Label {
id: dlg
required property int index
required property string name
text: index + ". " + name
Rectangle {
visible: dlg.index % 2
}
}
}
Is this still declarative?
ListView {
model: ContactModel { }
delegate: Label {
required property int index
required property string name
text: getText()
function getText(): string {
return index + ". " + name
}
}
}
import QtQuick 2.3
Item {
id: root
property int accumulatedValue: 0
Component.onCompleted: {
const someData = [1, 2, 3, 4, 5, 20]
for (let i = 0; i < someData.length; ++i) {
accumulatedValue = accumulatedValue + someData[i]
}
}
Text {
text: root.accumulatedValue.toString()
onTextChanged: console.log("text binding re-evaluated")
}
}
import QtQuick 2.3
Item {
id: root
property int accumulatedValue: 0
Component.onCompleted: {
const someData = [1, 2, 3, 4, 5, 20]
let temp = accumulatedValue
for (let i = 0; i < someData.length; ++i) {
temp = temp + someData[i]
}
accumulatedValue = temp
}
Text {
text: root.accumulatedValue.toString()
onTextChanged: console.log("text binding re-evaluated")
}
}
void MyRectangle::setRadius(int r)
{
m_radius = r;
emit radiusChanged();
}
Don’t use them.
Item {
id: root
property int borderWidth
Rectangle {
// No no...
border.width: borderWidth
}
}
Window {
onClosing: (event) => {
event.accepted = MySingletonClass.confirmExit()
}
Button {
background: Rectangle {
color: Theme.buttonBackground
}
}
}
// Contacts.qml
Item {
id: root
ListView {
model: MySingletonClass.contacts
delegate: Text { /* ... */ }
}
}
// Contacts.qml
Item {
id: root
property alias model: lv.model
ListView {
id: lv
delegate: Text { /* ... */ }
}
}
// ColorsWindow.qml
Window {
id: root
Column {
Repeater {
model: Palette.selectedColors
delegate: ColorViewer {
required property color color
required property string colorName
selectedColor: color
selectedColorName: colorName
}
}
}
}
See Issue #2 for related discussions.
// ColorsWindow.qml
Window {
property alias model: rp.model
Column {
Repeater {
id: rp
model: PaletteColorsModel { } // Alternatively
delegate: ColorViewer {
required property color color
required property string colorName
selectedColor: color
selectedColorName: colorName
}
}
}
}
Two ownership types:
See example for using properties for data customization
See this article for a real life example of a related bug in an application.
Q_PROPERTY( QObject* colors READ colors )
QObject* colors(); // Ownership remains in C++.
Q_INVOKABLE QObject* myData(); // Ownership is transferred to QML.
Profile first! Needs contributions.
Signals != Functions
Function -> Changes Internal State
Imperative form -> doSomething()
Signal -> Announces Internal State Change
Passive form -> somethingChanged()
.connect()
in QMLApplicationWindow {
id: root
property list<QtObject> myObjects: [
QtObject { signal somethingHappened() }, QtObject { signal somethingHappened() },
QtObject { signal somethingHappened() }, QtObject { signal somethingHappened() },
QtObject { signal somethingHappened() }, QtObject { signal somethingHappened() },
QtObject { signal somethingHappened() }, QtObject { signal somethingHappened() }
]
ListView {
cacheBuffer: 1 // Low enough we can resize the window to destroy buttons.
model: root.myObjects.length
delegate: Button {
text: "Button " + index
onClicked: root.myObjects[index].somethingHappened()
Component.onCompleted: root.myObjects[index].somethingHappened.connect(() => console.log(text))
Component.onDestruction: console.log("Destroyed #", index)
}
}
}
.connect()
in QML (Continued)ApplicationWindow {
id: root
property list<QtObject> myObjects: [
// ... Same model as previous code snippet
]
ListView {
cacheBuffer: 1 // Low enough we can resize the window to destroy buttons.
model: root.myObjects.length
delegate: Button {
id: dlg
text: "Button " + index
onClicked: root.myObjects[index].somethingHappened()
Component.onDestruction: console.log("Destroyed #", index)
Connections {
target: root.myObjects[index]
function onSomethingHappened() {
console.log(dlg.text)
}
}
}
}
}
// ColorPicker.qml
Rectangle {
id: root
signal colorPicked(color pickedColor)
ColorDialog {
onColorChanged: {
root.colorPicked(color)
}
}
}
// main.qml
Window {
ColorPicker {
onColorPicked: {
color = pickedColor
label.text = "Color Changed"
}
}
Label { id: label }
}
// ColorPicker.qml
Rectangle {
id: root
signal colorPicked(color pickedColor)
ColorDialog {
onColorChanged: {
root.color = color
root.colorPicked(color)
}
}
}
// main.qml
Window {
ColorPicker {
onColorPicked: {
label.text = "Color Changed"
}
}
Label { id: label }
}
Rule of thumb:
When communicating up, use signals.
When communicating down, use functions.
Item {
component Rect: Rectangle {
id: self
readonly property alias pressed: ma.containsPress
states: State {
when: ma.containsMouse
PropertyChanges { target: self; color: "red" }
}
MouseArea { id: ma; hoverEnabled: true }
}
Rect {
id: rect
states: State {
when: rect.pressed
PropertyChanges { target: rect; color: "yellow" }
}
}
}
width/height
or anchors
are set.// CheckBox.qml
Item {
id: root
property bool checked
property string text
Rectangle {
id: indicator
width: 50
height: 50
visible: root.checked
color: "red"
}
Label {
anchors {
left: indicator.right
verticalCenter: indicator.verticalCenter
}
text: root.text
}
}
// main.qml
Window {
CheckBox {
checked: true
text: "CheckBox"
}
Column {
width: 100
Repeater {
model: 5
delegate: CheckBox {
required property int index
width: parent.width
checked: index % 2 === 0
}
}
}
}
// CheckBox.qml
Item {
id: root
property bool checked
property string text
implicitWidth: indicator.implicitWidth + label.implicitWidth
implicitHeight: Math.max(indicator.implicitHeight, label.implicitHeight)
Rectangle {
id: indicator
width: height
height: parent.height * 0.5
implicitWidth: 50
implicitHeight: 50
visible: root.checked
color: "red"
}
Label {
id: label
anchors {
left: indicator.right
verticalCenter: indicator.verticalCenter
}
text: root.text
}
}
// main.qml
Window {
CheckBox {
checked: true
text: "CheckBox"
}
Column {
width: 100
Repeater {
model: 5
delegate: CheckBox {
required property int index
checked: index % 2 === 0
}
}
}
}
… our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. - Edsger W. Dijkstra, Go To Statement Considered Harmful
// Arrow function
root.value = Qt.binding(() => root.someOtherValue)
// The old way.
root.value = Qt.binding(function() { return root.someOtherValue })
// Variables
const value = 32;
let valueTwo = 42;
{
// Valid assignment since we are in a different scope.
const value = 32;
let valueTwo = 42;
}
const value = 32;
value = 42; // ERROR!
MouseArea {
// Good!
onClicked: (mouse) => {
}
// Bad...
onClicked: {
}
}
QML Coding Guidelines on GitHub - https://github.com/Furkanzmc/QML-Coding-Guide