QML: отличие оператора ":" Qt.binding от Binding
QML — замечательный инструмент. Но мало кто знает, как пользоваться им правильно. В этой коротенькой заметке я хочу предложить вашему вниманию некое негласное правило, которое сделает ваш код безопаснее для вас самих же. Ведь на QML так просто выстрелить себе в ногу.
Правило следующее: вот так писать не надо!
property var varOfRectangle: item.varOfItem
Надо вот так!
readonly property var varOfRectangle: item.varOfItem
Или вот так!
property var varOfRectangle
Т.е. либо обязательно ставим переменную в readonly, либо не присваиваем переменной вообще ничего, и биндим через Binding.
Item {
id: item
property var varOfItem
}
Rectangle {
id: rectangle
property var varOfRectangle
}
Binding {
target: rectangle
property: "varOfRectangle"
value: item.varOfItem
}
Я сказал слово «присваивание»? Именно так! В этом и заключается проблема! Оператор »: » делает тоже самое, как если бы вы присвоили биндинг через оператор »=».
Component.onCompleted: {
varOfRectangle = Qt.binding( function () { return item.varOfItem } )
}
А это значит, что вашу переменную varOfRectangle можно перезаписать другим значением, и она больше не будет ни на что забинжена.
onSomeVarChanged: {
...
parent.varOfRectangle = true
...
}
И вот вы усиленно меняете значение переменной varOfItem, в полной уверенности что она забинжена на varOfRectangle, а на самом деле нет.
А теперь о более сложном. О концепте QML, об идеологии, о парадигме вцелом.
Суть QML предполагает, что в программе нет времени, нет прошлого, не будущего, а значит нет настоящего нет порядка последовательности.
Зная всё написанное выше, вновь вернёмся к тому с чего начали, к примеру, как писать не надо.
property var varOfRectangle: item.varOfItem
Рассмотрим эту строчку ещё раз. Тут написано, что переменную можно как читать, так и записывать. Логично предположить, что прочитав переменную varOfRectangle мы получим значение переменной varOfItem. Так ли это? Можем ли мы гарантировать, что произойдёт первым: чтение или запись? Напомню, что после записи в эту переменную, она уже не будет забинжена varOfItem, как мы могли бы подумать, читая этот код.
И тут вновь возвращаемся к ключевой концепции QML: у программы нет времени. Мы не можем предсказать, что произойдёт первым, чтение или запись. Библиотека Qt обрабатывает события в любой последовательности, в разных условиях по разному, как посчитает наиболее оптимальным.
Ваш код на QML не должен зависеть от последовательности событий.
При использовании Binding, можно присваивать переменной другое значение в любое время — биндинг не потеряется, и останется рабочим.
Итог: используйте readonly при обьявлении переменной; если же предполагаете менять её значение через оператор »=», но хотите её на что-то забиндить — используйте Binding. Этот компонент управляем, его можно сделать активным или неактивным по условию. Это предотвратит ваш код от неожиданного поведения.
Нарушая это правило, программа становится зависимой от порядка чтения-записи, а это — нарушение идеологии QML и с вероятностью 100% станет той самой верёвкой в вашем коде, длина которой достаточна чтобы выстрелить себе в ногу.
Всех благ, и пишите в комментариях, что вы думаете об этом.