Связывание свойств
Свойству объекта можно присвоить статическое значение, которое остается постоянным до тех пор, пока ему явно не присвоено новое значение. Однако, для максимального использования QML и его встроенной поддержки динамического поведения объектов, большинство QML-объектов используют связывание свойств.
Связывания свойств — это ключевая функция QML, которая позволяет разработчикам задавать отношения между различными свойствами объектов. Когда значения зависимостей свойства изменяются, свойство автоматически обновляется в соответствии с заданным отношением.
За кулисами движок QML отслеживает зависимости свойства (то есть переменные в выражении связывания). При обнаружении изменения движок QML повторно оценивает выражение связывания и применяет новый результат к свойству.
Обзор
Для создания связывания свойства свойству присваивается выражение JavaScript, которое вычисляется до желаемого значения. В простейшем случае связывание может быть ссылкой на другое свойство. Рассмотрим следующий пример, где высота синего прямоугольника Rectangle связана с высотой его родителя:
Rectangle {
width: 200; height: 200
Rectangle {
width: 100
height: parent.height
color: "blue"
}
} Всякий раз, когда высота родительского прямоугольника изменяется, высота синего прямоугольника автоматически обновляется до того же значения.
Связывание может содержать любое допустимое выражение или оператор JavaScript, так как QML использует совместимый с стандартами движок JavaScript. Связывания могут получать доступ к свойствам объектов, вызывать методы и использовать встроенные объекты JavaScript, такие как Date и Math. Ниже приведены другие возможные связывания для предыдущего примера:
height: parent.height / 2
height: Math.min(parent.width, parent.height)
height: parent.height > 100 ? parent.height : parent.height/2
height: {
if (parent.height > 100)
return parent.height
else
return parent.height / 2
}
height: someMethodThatReturnsHeight() Ниже приведен более сложный пример, включающий больше объектов и типов:
Column {
id: column
width: 200
height: 200
Rectangle {
id: topRect
width: Math.max(bottomRect.width, parent.width/2)
height: (parent.height / 3) + 10
color: "yellow"
TextInput {
id: myTextInput
text: "Hello QML!"
}
}
Rectangle {
id: bottomRect
width: 100
height: 50
color: myTextInput.text.length <= 10 ? "red" : "blue"
}
} В предыдущем примере,
-
topRect.widthзависит отbottomRect.widthиcolumn.width -
topRect.heightзависит отcolumn.height -
bottomRect.colorзависит отmyTextInput.text.length
Синтаксически связывания могут иметь произвольную сложность. Однако, если связывание слишком сложное — например, включает несколько строк или императивные циклы — это может указывать на то, что связывание используется не только для описания отношений свойств. Сложные связывания могут снизить производительность кода, удобочитаемость и поддерживаемость. Может быть полезно перепроектировать компоненты со сложными связываниями или, по крайней мере, вынести связывание в отдельную функцию. Как общее правило, пользователи не должны полагаться на порядок вычисления связываний.
Создание связываний свойств из JavaScript
Свойство со связыванием автоматически обновляется при необходимости. Однако, если свойству позже присваивается статическое значение из оператора JavaScript, связывание будет удалено.
Например, прямоугольник Rectangle ниже изначально гарантирует, что его height всегда в два раза больше его width. Однако, при нажатии клавиши пробела текущее значение width*3 будет присвоено height как статическое значение. После этого height останется неизменным, даже если width изменится. Присвоение статического значения удаляет связывание.
import QtQuick 2.0
Rectangle {
width: 100
height: width * 2
focus: true
Keys.onSpacePressed: {
height = width * 3
}
} Если целью является присвоение прямоугольнику фиксированной высоты и остановка автоматических обновлений, то это не проблема. Однако, если целью является установление нового отношения между width и height, то новое выражение связывания должно быть заключено в функцию Qt.binding():
import QtQuick 2.0
Rectangle {
width: 100
height: width * 2
focus: true
Keys.onSpacePressed: {
height = Qt.binding(function() { return width * 3 })
}
} Теперь после нажатия клавиши пробела высота прямоугольника будет продолжать автоматически обновляться, всегда составляя в три раза его ширину.
Отладка перезаписи связываний
Распространённой причиной ошибок в QML-приложениях является случайное перезаписывание связываний статическими значениями из операторов JavaScript. Чтобы помочь разработчикам находить проблемы такого рода, движок QML может генерировать сообщения всякий раз, когда связывание теряется из-за императивных присвоений.
Для генерации таких сообщений необходимо включить информационные выводы для категории регистрации qt.qml.binding.removal, например, вызвав:
QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true")); Для получения дополнительной информации об включении вывода из категорий регистрации см. документацию QLoggingCategory.
Обратите внимание, что в некоторых случаях перезапись связываний вполне допустима. Любое сообщение, сгенерированное движком QML, следует рассматривать как диагностическое средство, а не как обязательный признак проблемы без дальнейшего исследования.
Использование this со связыванием свойств
При создании связывания свойства из JavaScript можно использовать ключевое слово this, чтобы сослаться на объект, который получает связывание. Это полезно для разрешения неоднозначностей с именами свойств.
Например, обработчик Component.onCompleted ниже определен в рамках области видимости Item. В этой области видимости width относится к ширине Item, а не к ширине Rectangle. Чтобы связать height Rectangle со своим собственным width, выражение связывания должно явно ссылаться на this.width (или, как альтернатива, rect.width):
Item {
width: 500
height: 500
Rectangle {
id: rect
width: 100
color: "yellow"
}
Component.onCompleted: {
rect.height = Qt.binding(function() { return this.width * 2 })
console.log("rect.height = " + rect.height) // prints 200, not 1000
}
} Примечание: Значение this не определено за пределами связываний свойств. Подробности см. в разделе Ограничения среды JavaScript.
См. также Размещение с помощью якорей.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/qtqml-syntax-propertybinding.html