Как определяются зависимости свойств QML? (и как ими манипулировать)
Свойство, связанное с выражением, обновляется при изменении чего-либо в выражении. Это называется зависимостью .
Иногда движок QML может обнаружить изменение, даже если выражение является вызовом функции без аргументов, в других случаях он не может этого сделать (например: mapToItem(item,0,0).x).
Другой пример несовершенства заключается в том, что установка значения элемента массива JS без переназначения самого массива обычно не создает сигнал onXxxxxChanged или не обновляет что-либо, ссылающееся на это значение массива.
Выражение с неиспользованным результатом (
x: {myForcedDependency; return myActualCalculation()}
) иногда предлагается вызвать зависимость .
Согласно этой статье KDAB и исходному коду Qt , выражение привязки не только оценивается, но и любые свойства, к которым "обращаются" во время этого, "захватываются" в нечто, называемое "охраной", тогда все свойства защиты в сигналах XxxxxChanged() связаны, но фактически детали этого процесса неясны.
Итак, мои вопросы:
Есть ли какие-то определенные правила разрешения зависимостей?
Как это на самом деле работает?
- Насколько глубоко QQmlEngine / V8 сканирует "доступы" к функциям, вызываемым выражением привязки, и что может помешать этому?
- Обнаружение зависимостей основано только на первой попытке разрешения свойств?
- Проверяются ли все возможные пути кода, даже если выполнение еще не достигнуто?
- Определяются ли в этих случаях нетривиальные обращения, такие как синтаксис объекта ["свойство"]?
- Что делать, если какой-то неисполненный код (в настоящее время) ошибочен (и не вызывает ошибки, но не может быть должным образом проанализирован)?
Как можно повлиять на процесс разрешения зависимостей?
- Есть ли способ избежать или заблокировать зависимость?
- Насколько я понимаю, промежуточное свойство "фильтра", которое на самом деле меняет свое значение только тогда, когда необходимо обновить, является предполагаемым способом, правильно?
- Есть ли способ принудительно установить зависимость?
- Является ли отправка сигнала «XxxxxChanged» вручную правильным / поддерживаемым способом принудительного обновления?
- Является ли добавление неиспользуемой ссылки законным / предполагаемым способом сделать это или неопределенным поведением, основанным на текущей причуде реализации?
- Есть ли способ избежать или заблокировать зависимость?
Любая информация была бы полезной, хотя я читал официальную документацию по свойствам QML, привязкам QML и выражениям JavaScript и не нашел конкретного объяснения - если вы обратитесь к официальной документации, укажите соответствующие части.
Обратите внимание, что я не прошу вас проверять, работает ли что-либо из этого в вашей системе, но должно ли это работать - можно ли на это положиться
2 ответа
Это будет иметь больше смысла, если вы просто будете думать о привязках как о связанных сигналах. Если у вас что-то вроде этого:
property int x: y
Это как в C++:
connect(this, &SomeClass::yChanged, [this]() { x = y; });
То же самое и с выражениями:
property int x: y + z
будет эквивалентно:
connect(this, &SomeClass::yChanged, [this]() { x = y + z; });
connect(this, &SomeClass::zChanged, [this]() { x = y + z; });
То же самое и с вызовами функций:
property int x: someFunc()
function someFunc() {
return y;
}
Связывания не обновляются только тогда, когда нет сигнала onChanged для подключения или сигнал onChanged не генерируется по какой-либо причине.
property int x: cppObject.invokable()
В приведенном выше случае единственное свойство, к которому можно подключиться, - это
cppObject
. Если
invokable
ссылается на другие свойства, они не будут связаны с
x
и поэтому привязка не обновляется.
property var array: [1, 2, 3]
property int x: array[0]
function updateArray() {
array = [2, 4, 6]
arrayChanged() // Manually call the onChanged signal to update `x`
}
var
свойства не уведомляют по умолчанию (по какой-то причине). Таким образом, в этом случае мы должны вручную вызвать измененный сигнал, но тогда привязка все равно будет работать.
Для a испускается только тогда, когда есть прямое присвоениеvar
само по себе, а не свойство какого-либо объекта, на который оно ссылается. Это также исключает модификацию содержимого массива, поскольку массивы JS являются объектами JS.
Это согласуется с тем, что QML является расширением JS. В JS вы можете изменитьprop
в этом коде, потому что означает толькоvariable
всегда будет ссылаться на один и тот же объект:
const variable = { prop: 'value' };
Точно так же только прямые присвоения константным переменным считаются попытками изменения, когда JS применяетconst
, QML выдает толькоonChanged
по прямым поручениямproperty var
.
Исходя из C++, мне нравится сравнивать переменные JS со значением объекта с указателями:
SomeClass *variable = new SomeClass();
SomeClass *const variable = new SomeClass(); //const pointer to mutable object
Опять же, изменение упомянутого объекта не рассматривается как изменение переменной.