Крайне удобным способом позиционирования различных QML компонентов является использование так называемых Anchors. Что в переводе ближе всего к "якорям", но мне русификация такого типа обычно не слишком нравится. Поэтому я, хоть специально на этом не концентрируюсь и внимания не обращаю, тем не менее в тексте на автомате скорее всего буду писать "anchors". Минутка филологии завершена, давайте рассмотрим несколько основных практических примеров использования данного механизма.
QML Anchors. Краткие теоретические сведения.
Итак, идея заключается в том, что у каждого элемента есть некий набор свойств, благодаря которым можно полностью управлять его расположением относительно других элементов. На примере абстрактного элемента:
Перечень данных свойств включает в себя 7 пунктов:
- top
- bottom
- left
- right
- horizontalCenter
- verticalCenter
- baseline
По сути мы получаем 7 линий, задавая положение которых, осуществляем перемещение компонента, к которому эти линии относятся 👍 Все линии изображены на схеме, поэтому не останавливаемся, рассмотрим конкретные варианты использования. Как вы заметили, baseline не изображена, о ней речь пойдет чуть ниже.
QML Anchors. Примеры позиционирования.
Начинаем с пустого Qt Quick приложения, объектом изменений будет исключительно файл main.qml:
import QtQuick 2.15 import QtQuick.Window 2.15 Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" }
Начнем вопреки логике с не упомянутого ранее свойства - anchors.fill
. Его установка эквивалентна изменению top
, bottom
, left
и right
одновременно:
import QtQuick 2.15 import QtQuick.Window 2.15 Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { color: "#008080" anchors.fill: parent } }
В результате Rectangle
займет все пространство окна:
Аналогичного эффекта можно было добиться так:
anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom
Собственно, экономия и удобство anchors.fill
налицо. Теперь допустим нам нужно добиться такого эффекта для двух прямоугольников:
Высота верхнего прямоугольника пусть будет фиксированной, а нижнего - определяться тем свободным пространство окна, которое ему останется. Anchors получаем следующие:
Ровно так и делаем и получаем в точности такой результат, как требовалось:
Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { id: blueRectangle color: "#008080" anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right height: 320 } Rectangle { id: greenRectangle color: "#3CB371" anchors.top: blueRectangle.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right } }
При этом для верхнего объекта мы не задаем anchors.bottom
, поскольку его высота задана явно. А если мы помимо height
задали еще и anchors.bottom
, то возникло бы противоречие - высота задана как относительно, при помощи anchors.top
и anchors.bottom
, так и абсолютно через height
. Такие коллапсы недопустимы. Это же касается и задания ширины, да и любых аспектов абсолютного позиционирования, которые могут конфликтовать с позиционированием при помощи anchors.
С "основными" линиями - top, bottom, left, right - все понятно, рассмотрим оставшиеся 3 варианта. Снова оставляем один Rectangle
, зададим ему фиксированные размеры и поставим задачу расположить его четко по центру окна:
Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { id: blueRectangle color: "#008080" width: 320 height: 240 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter } }
Суть здесь также проста. Anchors - это конкретные линии конкретного объекта. Поэтому мы имеем в наличию линию, соответствующую horizontalCenter
, как у blueRectangle
, так и у его родителя, которым в данном случае является основное окно приложения. И затем мы просто задаем положение этой линии у прямоугольника, чтобы она совпадала с аналогичной у окна:
Как и в случае с anchors.fill
есть дополнительный вариант, упрощающий жизнь, и в данном случае это - anchors.centerIn
. Аналогичного позиционирования в данном примере мы могли достигнуть и так:
anchors.centerIn: parent
Пройдемся по свойству baseline
, которое часто незаслуженно упоминается лишь поверхностно парой фраз. Данная линия относится к воображаемой линии, на которой находится текст. У рассмотренных прямоугольников текст отсутствует - для них baseline
совпадает с top
. Возьмем прямоугольник и кнопку с текстом и посмотрим на разницу:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { id: blueRectangle color: "#008080" height: 240 anchors.left: parent.left anchors.right: myButton.left anchors.baseline: parent.verticalCenter } Button { id: myButton text: qsTr("My Button") anchors.right: parent.right anchors.baseline: parent.verticalCenter } }
Да, на всякий напоминаю, для Button добавляем:
import QtQuick.Controls 2.15
Результат закономерен с учетом вышеописанного:
QML Anchors. Margins, offsets.
При использовании данной концепции позиционирования редко обходится без задания полей - margins:
То есть margins задает размер пустого пространства между линиями top, bottom, left, right и непосредственно самим элементом. Реализуется свойствами:
- anchors.topMargin
- anchors.bottomMargin
- anchors.leftMargin
- anchors.righrMargin
- и также есть обобщающее свойство anchors.margins, задающее все четыре предыдущих одновременно
Offsets же задают смещения трех неохваченных линий, а именно - horizontalCenter, verticalCenter, baseline. Рассмотрим конкретный пример для случая с двумя прямоугольниками: добавляем поля сверху и слева - для верхнего, снизу и справа - для нижнего:
Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { id: blueRectangle color: "#008080" anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 30 anchors.topMargin: 30 height: 320 } Rectangle { id: greenRectangle color: "#3CB371" anchors.top: blueRectangle.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: 15 anchors.bottomMargin: 15 } }
Задав все поля одновременно, добились бы такого эффекта:
Window { width: 640 height: 480 visible: true title: qsTr("QML Anchors Review") color: "#303030" Rectangle { id: blueRectangle color: "#008080" anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.margins: 30 height: 320 } Rectangle { id: greenRectangle color: "#3CB371" anchors.top: blueRectangle.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right anchors.margins: 30 } }
Еще по плану было разобрать AnchorChanges
, но опять же хочется не несколькими общими предложениями отделаться, а наглядные примеры рассмотреть, поэтому оставлю до следующей статьи.
Понравилось как все доступно вы описываете. Жду следующую статью о AnchorChanges.