Порядок и способ оценки связывания свойств в QML

Насколько я понимаю, когда свойства используются в выражениях привязки, их сигналы NOTIFY связаны, чтобы сигнализировать о переоценке выражения каждый раз, когда значение свойства изменяется.

Итак, рассмотрим этот тривиальный пример:

Rectangle {
    width: 200
    height: width - 100

    Text {
        text: "value is " + (parent.width + parent.height)
    }
}

В нем свойство height связано со свойством width, а свойство text связано с обоими.

В этом примере непонятен порядок действий. Я имею в виду, что если width изменится, он переоценит оба выражения, которые на него ссылаются. Но width также изменит height, что также вызовет оценку text.

Значит ли это, что свойство text оценивается дважды? Один раз при смене width и еще раз при смене width на height? Или, может быть, в QML есть какой-то механизм оптимизации этого поведения, например, сигналы уведомления не запускают фактическую переоценку, а только помечают выражения как «грязные», и они переоцениваются на следующей итерации цикла событий, когда все сигналы были распространены? И даже в этом случае, как движок узнает, что нужно обновить height перед обновлением text, чтобы избежать двойной переоценки последнего? Или, может быть, соединение прямое, а не в очереди, и используется какой-то более сложный механизм для определения порядка переоценки? Или, может быть, ничего подобного нет, и text может на самом деле переоценить дважды, если это будет произвольный порядок?

Мне действительно нужно понять, как это работает, потому что у меня есть проект, в котором я императивным образом изменяю несколько свойств нескольких объектов QML на стороне C++, которые связаны со стороной QML, и я получаю очень непоследовательное и неустойчивое поведение, поэтому я определенно необходимо учитывать, как они работают.


person Community    schedule 20.11.2014    source источник


Ответы (1)


Да. похоже, вы правы, и text будет обновляться дважды. Простой пример:

Rectangle {
    id: testRect
    width: 200
    height: width - 100

    Text {
        text: "value is " + (parent.width + parent.height)
        onTextChanged: {
            console.log("text was changed (" + parent.width + "," + parent.height + ")");
        }
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            testRect.width = 300
        }
    }
}

выход:

qml: text was changed (200,100) 
qml: text was changed (300,100) 
qml: text was changed (300,200)

Я предполагаю, что это простое поведение и обновление соответствующего свойства при изменении некоторых свойств, на которых основан этот элемент.

Qt docs советы, чтобы избежать такой ситуации - However, if a binding is overly complex - such as involving multiple lines, or imperative loops - it could indicate that the binding is being used for more than describing property relationships. Complex bindings can reduce code performance, readability, and maintainability. It may be a good idea to redesign components that have complex bindings, or at least factor the binding out into a separate function.

person folibis    schedule 20.11.2014
comment
Я нашел kdab.com/qml-engine-internals-part-2 -bindings в разделе комментариев К вашему сведению: при первой загрузке компонента движок QML попытается оценить привязки в порядке, сводящем к минимуму повторные оценки привязок, но я думаю, что это не имеет большой ценности, так как не удается даже в таких простых случаях, как приведенный выше пример. Это кажется удивительно непрофессиональным для Qt... - person ; 21.11.2014