QML: отличие оператора ":" Qt.binding от Binding

7834101ba70a243a3de68a808f726fcf

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% станет той самой верёвкой в вашем коде, длина которой достаточна чтобы выстрелить себе в ногу.

Всех благ, и пишите в комментариях, что вы думаете об этом.

© Habrahabr.ru