Как определяются зависимости свойств 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

Опять же, изменение упомянутого объекта не рассматривается как изменение переменной.

Другие вопросы по тегам