Привязки больше похожи на мета-свойство, чем на фактическое значение. Это легко понять, если представить, как это работает со стороны c ++.
Привязки реализуются с использованием сигналов и слотов. Простая строка QML
text: foo.text
в качестве примера будет эквивалентен следующему коду c ++ (упрощенно):
// first: call the getter of text on foo, and the setter on this
this->setText(foo->text());
// second: connect the change signal of foo to this
connect(foo, SIGNAL(textChanged(QString)),
this, SLOT(setText(QString)));
Как видите, привязка в основном: «Присвойте мне текущее значение, и всякий раз, когда ваше значение изменяется, обновляйте мое значение до вашего». Но поскольку у «this» все еще есть собственная копия текста, вы можете изменить ее, вызвав this->setText("something")
, не нарушая привязку (или, в терминах c ++ - сигнальное соединение)
Это также объясняет 2-й (и 1-й) эксперимент: всякий раз, когда вы изменяете текст t2 в GUI, внутренний текст t2 обновляется. Однако, поскольку привязка все еще существует, каждый раз, когда вы изменяете t1, t1 испускает сигнал textChanged
и, таким образом, также обновляет t2.
Теперь для 3-го эксперимента это немного сложно. Код на C ++ сильно упрощен и объясняет только то, что происходит, а не то, как он на самом деле работает. В третьем случае мы должны взглянуть на javascript сторону qml. Более конкретно: Как создаются привязки из JavaScript:
// the qml line
text: foo
// is eqivalent to the js
t1.text = Qt.binding(function(){return foo;})
Таким образом, вы на самом деле не присваиваете значение t1.text
, а «объект привязки». (Функция Qt.binding
совершает магию и возвращает такой объект). Это внутренне делает то же самое, что и код c ++, приведенный выше, но с одним отличием. Когда вы назначаете новое значение для t1.text
, как вы делали это для кнопки, старая привязка удаляется вместе с сигнальным соединением, когда вы заменяете объект привязки новым значением.
Таким образом, в вашем коде JS в кнопке вы заменяете объект привязки значением «bar», тем самым уничтожая его. Редактирование текста из графического интерфейса пользователя не разрушает привязку, так как изменяется только внутреннее значение, и фактически свойство не присваивается свойству из QML.
РЕДАКТИРОВАНИЕ: Теперь причина, по которой последующие нажатия кнопок ничего не делают: после однократного нажатия кнопки foo устанавливается на «bar», что вызывает сигнал textChanged
и, таким образом, изменяет t1 , Однако, когда вы в следующий раз нажмете кнопку, и foo снова будет установлен на bar, он ничего не делает, потому что он уже «bar». Вы ничего не меняете, устанавливая на то же значение, что и сейчас. Представьте себе реализацию метода установки следующим образом:
void setText(QString text) {
if(this->text == text)
return;
this->text = text;
emit textChanged(text);
}
Если вы измените свой код, например, так:
Button { x: 100; onClick: foo = t1.text + "bar" }
Он всегда будет работать и обновлять foo соответственно, так как это выражение всегда генерирует новое значение для foo.
Я надеюсь, что смогу объяснить поведение, понятное вам.