QML — это декларативный язык описания пользовательского интерфейса, построенный поверх объектной модели Qt. Несмотря на визуальную простоту, QML опирается на строгие принципы: объекты, свойства, сигналы и слоты. Понимание этих основ — критически важно для написания поддерживаемых Qt Quick-приложений.
В этой статье разберём:
- как устроен объект в QML
- что такое свойства и биндинги
- как работают сигналы и обработчики
- как QML взаимодействует с C++
QML как объектная иерархия
Любой QML-файл описывает дерево объектов. Каждый элемент — это экземпляр класса Qt.
Пример:
Rectangle {
width: 200
height: 100
Text {
text: "Hello QML"
}
}
Здесь:
Rectangle— объект верхнего уровняText— дочерний объект- вложенность формирует визуальную и логическую иерархию
Важно:
- порядок объектов имеет значение
- дочерние элементы наследуют контекст родителя
- уничтожение родителя уничтожает всех потомков
Свойства (Properties)
Свойства — основа QML. Почти всё в QML — это свойство.
Присваивание значения
width: 300 color: "red" visible: true
Тип свойства определяется классом компонента.
Примеры типов:
int,realstringboolcolorurlvar
Property Binding (реактивность)
Ключевая особенность QML — реактивные биндинги.
Rectangle {
width: parent.width / 2
}
Значение width автоматически обновится при изменении parent.width.
Это не копирование значения, а выражение, которое Qt пересчитывает при изменениях зависимостей.
Пользовательские свойства
Вы можете объявлять собственные свойства.
Rectangle {
property int counter: 0
property string title: "Заголовок"
}
Такие свойства:
- участвуют в биндингах
- могут быть доступны из C++
- поддерживают сигналы изменения
Сигналы в QML
Сигнал — это уведомление о событии.
Пример встроенного сигнала:
Button {
onClicked: console.log("Нажато")
}
clicked — сигналonClicked — обработчик сигнала
Пользовательские сигналы
Вы можете объявить собственные сигналы.
Item {
signal accepted(string value)
Button {
text: "OK"
onClicked: accepted("done")
}
}
Сигнал можно:
- обработать в родителе
- подключить из C++
- использовать для разделения логики
Слоты и обработчики
В QML слоты не объявляются явно, как в C++.
Вместо этого используется:
onSignalName- JavaScript-функции
- автоматическое сопоставление
Пример:
MouseArea {
onEntered: {
parent.color = "lightgray"
}
}
JavaScript в QML
QML использует встроенный JavaScript-движок.
function increment() {
counter++
}
JavaScript применяется для:
- простой логики
- вычислений
- обработки сигналов
Важно:
- это не полноценный Node.js
- тяжёлую логику следует выносить в C++
Связь сигналов и свойств
Очень распространённый паттерн:
property bool active: false
Button {
text: active ? "ON" : "OFF"
onClicked: active = !active
}
Сигнал изменяет свойство
Свойство автоматически обновляет UI
Связь с C++
QML напрямую работает с:
Q_PROPERTYQ_INVOKABLE- сигналами
QObject
Пример:
Text {
text: backend.status
}
QML подписывается на statusChanged автоматически.
Частые ошибки
Ошибка: присваивание вместо биндинга
width = parent.width // неверно
Правильно:
width: parent.width
Ошибка: бизнес-логика в QML
→ сложно тестировать и сопровождать
Ошибка: циклические биндинги
→ предупреждения и неопределённое поведение
Как читать QML-код правильно
Рекомендуемый порядок чтения:
- корневой объект
- пользовательские свойства
- сигналы
- визуальная иерархия
- обработчики событий
Итог
QML — это:
- объектная модель
- реактивные свойства
- событийная архитектура
- декларативное описание UI
