Pull to refresh

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

Level of difficultyMedium
Reading time2 min
Views1.1K

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

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

Tags:
Hubs:
Total votes 6: ↑5 and ↓1+7
Comments9

Articles