Введение
Предыдущие статьи цикла иногда использовали абсолютные координаты (x: 50; y: 50) для простоты иллюстрации — в реальных приложениях позиционирование почти всегда строится через anchors (якоря) или layout-элементы, дающие декларативное, автоматически адаптирующееся позиционирование без явного, «хрупкого» указания точных пиксельных координат.
Концепция
Anchors позволяют привязать край или центр одного элемента к краю/центру другого элемента (обычно родителя или соседа) — anchors.left: parent.left, anchors.centerIn: parent, anchors.fill: parent — что автоматически поддерживает корректное позиционирование при изменении размеров родителя или других элементов, на которые сделана привязка, без необходимости вручную пересчитывать координаты. Layout-элементы (Row, Column, Grid, а также более продвинутые RowLayout/ColumnLayout/GridLayout из модуля Qt Quick Layouts) автоматически располагают дочерние элементы согласно заданной схеме (в ряд, в столбец, в сетку), беря на себя автоматический пересчёт позиций при изменении количества дочерних элементов или их размеров, что особенно ценно при динамическом, изменяющемся во время выполнения наборе элементов.
Пример кода: Anchors и layout-системы Qt Quick
// Anchors — позиционирование через привязку краёв, без абсолютных координат
import QtQuick
Rectangle {
id: root
width: 400; height: 300
Rectangle {
id: header
anchors.top: root.top
anchors.left: root.left
anchors.right: root.right
height: 60
color: "darkslateblue"
}
Rectangle {
id: sidebar
anchors.top: header.bottom // привязка к НИЖНЕМУ краю header, а не к root напрямую
anchors.bottom: root.bottom
anchors.left: root.left
width: 100
color: "lightgray"
}
Rectangle {
id: content
anchors.top: header.bottom
anchors.bottom: root.bottom
anchors.left: sidebar.right // привязка к ПРАВОМУ краю sidebar
anchors.right: root.right
color: "white"
}
// При изменении root.width/height ВСЯ компоновка автоматически адаптируется —
// ни одна координата не была указана в абсолютных пикселях напрямую
}
// RowLayout/ColumnLayout — Qt Quick Layouts для автоматического распределения пространства
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
ColumnLayout {
anchors.fill: parent
spacing: 8
RowLayout {
Layout.fillWidth: true
Label { text: "Имя:" }
TextField {
Layout.fillWidth: true // занимает всё ОСТАВШЕЕСЯ горизонтальное пространство
}
}
Button {
text: "Отправить"
Layout.alignment: Qt.AlignRight
}
}
Пояснения к коду
Цепочка привязок header → sidebar (привязанный к header.bottom) → content (привязанный к header.bottom и sidebar.right) показывает типичный паттерн построения макета «шапка-боковая панель-контент» — каждый элемент привязан к соседним элементам, а не к абсолютным координатам, и весь макет автоматически адаптируется при изменении размеров root без какого-либо дополнительного кода для пересчёта позиций. Layout.fillWidth: true для TextField внутри RowLayout демонстрирует ключевую возможность Qt Quick Layouts, недоступную через простые anchors напрямую — автоматическое распределение оставшегося доступного пространства между несколькими дочерними элементами, что особенно важно для форм и других интерфейсов с переменным количеством или размером элементов, заранее не предсказуемым жёстко зашитыми anchors.
Подводные камни
- Смешивание anchors и явных абсолютных координат (
x/y/width/height) для одного и того же элемента без понимания, как они взаимодействуют — если для одного измерения (например, ширины) задан как явныйwidth, так и одновременно противоречащая ему параanchors.left/anchors.right(которая сама определяет ширину через расстояние между двумя точками привязки), возникает конфликт, разрешаемый движком QML не всегда интуитивно очевидным образом, и для предсказуемого результата стоит явно выбрать один из подходов (либо anchors определяют размер, либо явныйwidth) для каждого конкретного измерения каждого элемента. - Создание циклических привязок anchors (элемент A привязан к элементу B, который одновременно привязан обратно к элементу A) — аналогично циклическим привязкам свойств (статья 481), это приводит к неопределённому или ошибочному поведению, и граф зависимостей anchors должен оставаться ацикличным, как и для обычных привязок свойств.
- Использование anchors для элементов без общего родителя (или не находящихся в отношении «родитель-потомок»/»соседи через общего родителя») — anchors корректно работают только для элементов в определённых, ограниченных отношениях друг к другу (один к другому при общем родителе, или потомок к собственному родителю), и попытка привязать произвольные, не связанные подобным образом элементы друг к другу не сработает или приведёт к ошибке.
- Использование исключительно anchors для сложных, динамических по содержимому макетов, где более подходящим решением были бы Layout-элементы — anchors отлично подходят для относительно статичной, заранее известной структуры (как пример «шапка-сайдбар-контент»), но для динамически изменяющегося количества или порядка элементов (формы с переменным набором полей, списки настраиваемой длины) ручное построение цепочки anchors значительно более хрупко и многословно по сравнению с использованием
RowLayout/ColumnLayout/GridLayout, автоматически адаптирующихся к изменению набора дочерних элементов.