Связывание свойств
Свойству объекта можно присвоить статическое значение, которое остается постоянным до его явного изменения. Однако, чтобы в полной мере использовать 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/archives/qt-5.11/qtqml-syntax-propertybinding.html