Комментарии 20
Если хочется забиндить свойства внутреннего компонента в другой компонент то проще всего сделать это через alias который создает bi-directional binding c и в целом решает полностью описанную Вами проблему.
Можно пример? Или ссылку на пример? Было бы здорово.
Item {
id: item
property var varOfItem
}
Rectangle {
id: rectangle
property alias varOfRectangle: item.varOfItem
}
Кстати, хорошее решение. Тогда зачем нужен readonly? :)
readonly используется для кейсов где свойство инициализируется каким-то значением и в дальнейшем не может быть изменено. Удобно им пользоваться для случаев когда создается свой компонент и надо вытащить наружу какие-то свойства но извне их менять запрещено. Например я частенько вытаскиваю размер шрифта который используется внутри моего компонента наружу но менять его извне бессмысленно.
Для вычисляемых свойств использовать.
Например, количество детей элемента.
Так как нет универсальной логики, что делать при записи в такое свойство
Именно по этому я поместил сей материал в раздел "Мнение". Как раз думаю в этом направлении.
Ведь получается, что если мы где то считываем значение переменной varOfRectangle, то какая нам разница, от куда она получила это значение?
property var varOfRectangle: item.varOfItem
...
property var ourProblemVar: varOfRectangle
В этом куске кода мы имеем проблему с ourProblemVar. Мы думали что получим значение из item.varOfItem. Но его не получаем, поскольку varOfRectangle где то в другом месте был переназначен.
Резонно задать вопрос: а какая нам разница, от куда получено значение varOfRectangle, если мы на него биндимся? Если разница всё таки есть, то тогда так и надо писать:
property var ourProblemVar: isCondition ? varOfRectangle : item.varOfItem
Вот и будем получать гарантировано что хотим.
alias который создает bi-directional binding
Имеенно так. Именно bi-directional binding мне сейчас нужен! И я долго думал как его сделать, поскольку есть проблема: компонент, к которому надо сделать алиас, находится внутри Loader-а.
У меня есть ListView внутри Loader-а, который грузится какое то время, и есть currentIndex из файла конфигурации, который тоже грузится не сразу. И мне как то надо их свести вместе :)
Но это уже совсем другая история...
А так, да, alias, сейчас смотрю в этом направлении, спасибо!
Тем не менее, логика статьи мне кажется всё равно актуальной. Зачем писать:
property var varOfRectangle: item.varOfItem
... когда varOfRectangle всё равно не будет равен item.varOfItem? А если и будет, то хрен знает когда и как надолго. Мне кажется, тут лучше поставить readonly.
Если же мы где то хотим эту переменную переназначать, то зачем тогда ей присваивать Qt.binding( function () { return item.varOfItem } ) ? Ведь это так же лишено смысла.
Вот и получается, что такая форма записи логически не приводит в багу, но и смысла в ней нет. Либо присваиваем Qt.binding и пишем readonly, либо нехрен присваивать если всё равно перезапишешь.
Думаю, для полноты картины стоит ещё пройтись и по default и по required, чтобы картина присвоения значения переменных была полной.
property var varOfRectangle: item.varOfItem
Тем не менее, логика статьи мне кажется всё равно актуальной. Зачем писать:
Итак давайте все же начнем сначала, когда мы пишем код выше то значит что мы априори подразумеваем что нам не надо управлять varOfRectangle самостоятельно а чтобы он присвоился автоматически из item.varOfItem. Т.е. биндинг по природе своей подразумевает что мы отдаем присвоение какой-то переменной некому автоматическому механизму. Если Вы сделали так то зачем начали присваивать его вручную? Если Вам необходимо делать вручную или Вас не устраивает как работает биндинг то никто не мешает написать например так:
Item {
id: item
property var varOfItem
onVarOfItem: {
rectangle.varOfRectangle = item.varOfItem
}
}
Rectangle {
id: rectangle
property var varOfRectangle
onVarOfRectangle: {
item.varOfItem = rectangle.varOfRectangle
}
}
Таким образом можно сделать биндинг просто кодом.
У меня есть ListView внутри Loader-а, который грузится какое то время, и есть currentIndex из файла конфигурации, который тоже грузится не сразу. И мне как то надо их свести вместе :)
Если интересно вот тут можете посмотреть как реализовано https://github.com/anilibria/anilibria-winmaclinux/blob/master/src/Views/OnlinePlayer.qml#L164 нечто похоже по описанию как Вам требуется.
Идея интересная. Мы писали CodingStyle.md
где явно не рекомендовали использовать JavaScript код вместо биндингов в т.ч.и потому, что подобный код
Component.onCompleted: {
varOfRectangle = item.varOfItem
}
может биндинг нарушить, разорвать. Нарушается целостность программы. readonly
свойство с binding (присваиванием) решает эту проблему и запрещает менять биндинг. Я бы добавил такое правило в новом CodingStyle.md
. Спасибо за идею!
Мы писали
CodingStyle.md
где явно не рекомендовали использовать JavaScript код вместо биндингов в т.ч.и потому
На самом деле это зависит от того как именно пишется приложение, если вся логика находиться в C++ то можно впринципе не использовать JavaScript а QML использовать как макет интерфейса. Но вот если приложение QML only или если у Вас дизайнеры/верстальщики участвуют в верстке QML такое вряд ли возможно, присвоение свойств через оператор = в JS функциях обычная практика для сложного дизайна.
readonly
свойство с binding (присваиванием) решает эту проблему и запрещает менять биндинг.
Добавление readonly возможно только в своих компонентах, поэтому фундаментально это проблему не решит. К тому же никто не мешает через js менять не значение а сам binding который по сути является функцией Qt.binding
.
если у Вас дизайнеры/верстальщики участвуют в верстке QML такое вряд ли возможно,
Не участвуют и не должны.
присвоение свойств через оператор = в JS функциях обычная практика для сложного дизайна.
Это неправильно! Происходит от незнания и непонимания QML. Это очень сильно ухудшает производительность, увеличивает тех долг, сильно усложняет сопровождение и поддержку, ухудшает расширяемость кода и т.п. Плавали - знаем! Поэтому подобную практику пресекли на корню.
Это неправильно! Происходит от незнания и непонимания QML. Это очень сильно ухудшает производительность, увеличивает тех долг, сильно усложняет сопровождение и поддержку, ухудшает расширяемость кода и т.п. Плавали - знаем! Поэтому подобную практику пресекли на корню.
Это зависит от того для чего Вы делаете и что Вы делаете. Большое количество биндингов и глубина цепочки этих самых биндингов также легко может стать причиной плохой производительности особенно на слабом железе поэтому не все так однозначно.
Большое количество биндингов и глубина цепочки этих самых биндингов также легко может стать причиной плохой производительности особенно на слабом железе поэтому не все так однозначно.
Возможно конечно, но я не сталкивался даже на слабом железе и с большим количеством биндингов. Но я говорю в сравнении: JS будет ещё хуже работать вне биндингов, будет гораздо менее производительным и значительно ухудшит архитектуру и расширяемость: QML декларативный, JS - процедурный. По моему опыту злоупотребление JS происходит от непонимания QML.
JS будет ещё хуже работать вне биндингов, будет гораздо менее производительным и значительно ухудшит архитектуру и расширяемость
Хорошо сделаем синтетический тест на сравнение чтобы убедиться что JS "будет гораздо менее производительным". Использую Qt 6.6 на Intel Core i9x2 2.80г, память 16Гб. Сделал вот такой вот простенький пример для биндинга :
import QtQuick
Window {
width: 640
height: bindingItem.bindingValue
visible: true
title: qsTr("Hello World")
QtObject {
id: bindingItem
property int bindingValue: 200
}
MouseArea {
anchors.fill: parent
onPressed: {
for (let i = 0; i < 1000; i++) {
bindingItem.bindingValue = bindingItem.bindingValue + 1;
}
}
}
}
Запустил профайлинг 5 раз, средний результат на скриншоте (разница между тестами в несколько миллисекунд).

Идем далее и проверим кейс с присвоением этого же поля из скрипта переписав код так:
import QtQuick
Window {
id: root
width: 640
height: 200
visible: true
title: qsTr("Hello World")
MouseArea {
anchors.fill: parent
onPressed: {
for (let i = 0; i < 1000; i++) {
root.height = root.height + 1;
}
}
}
}

Запустил профайлинг 5 раз, средний результат на скриншоте (разница между тестами в 10 миллисекунд).
Ну и последним проверим кейс с биндингом из С++:
import QtQuick
import TestBinding
Window {
width: 640
height: testCppBinding.bindingValue
visible: true
title: qsTr("Hello World")
TestCppBinding {
id: testCppBinding
}
MouseArea {
anchors.fill: parent
onPressed: {
testCppBinding.changeBinding();
}
}
}
#ifndef TESTCPPBINDING_H
#define TESTCPPBINDING_H
#include <QObject>
#include <QQmlEngine>
class TestCppBinding : public QObject
{
Q_OBJECT
Q_PROPERTY(int bindingValue READ bindingValue WRITE setBindingValue NOTIFY bindingValueChanged FINAL)
QML_ELEMENT
private:
int m_bindingValue { 200 };
public:
explicit TestCppBinding(QObject *parent = nullptr);
int bindingValue() const noexcept { return m_bindingValue; }
void setBindingValue(int bindingValue) {
if (m_bindingValue == bindingValue) return;
m_bindingValue = bindingValue;
emit bindingValueChanged();
}
Q_INVOKABLE void changeBinding() {
for (int i = 0; i < 1000; i++) {
setBindingValue(m_bindingValue + 1);
}
}
signals:
void bindingValueChanged();
};
#endif // TESTCPPBINDING_H
Запустил профайлинг 10 раз потому что был больший разброс, средний результат на скриншоте (разница между тестами в 100 миллисекунд).

Лишние 100 миллисекунд полагаю тратятся на клей между C++ и QML.
Результаты разные конечно но "гораздо менее производительным" какой-то из этих вариантов не стал точно.
Еще бы хотелось узнать от Вас примеры "ухудшит архитектуру и расширяемость".
QML декларативный, JS - процедурный
В соседнем лагере где HTML декларативный, JS - процедурный никого особо не смущает ничего :)
По моему опыту злоупотребление JS происходит от непонимания QML.
Стоит уточнить только злоупотребление или просто употребление?
Хорошо сделаем синтетический тест на сравнение чтобы убедиться что JS "будет гораздо менее производительным".
Нет, мы этого делать не будем, а просто прочитаем документацию: Prefer Declarative Bindings Over Imperative Assignments
Еще бы хотелось узнать от Вас примеры "ухудшит архитектуру и расширяемость".
Этот момент также хорошо описан по ссылке выше. А по опыту выкидывание JS сокращало код в 2-3 раза минимум. Если логику держать в JS сразу возникают сложности с наследованием, декомпозицией, оптимизацией кода и т.п. Т.к. сразу в новые или декомпозированные элементы нужно сразу тащить весь JS код.
В соседнем лагере где HTML декларативный, JS - процедурный никого особо не смущает ничего :)
Ещё как смущает: HTML совершенно отличный от QML - там нет биндингов и машины конечных состояний. Т.е. без JS HTML не работает вообще - статичный полностью. Про сравнение производительности вообще молчу: Qt сравнивала не раз.
Нет, мы этого делать не будем, а просто прочитаем документацию
В моем бенчмарке исследуется вопрос производительности биндинга против присвоения через JS и C++, и Ваша ссылка вообще не имеет никакого отношения к нему ровно как и остальные две написанные в сообщении ниже.
А по опыту выкидывание JS сокращало код в 2-3 раза минимум.
А функционал тоже выкидывался вместе с кодом?
Если логику держать в JS сразу возникают сложности с наследованием, декомпозицией, оптимизацией кода
агрегацией, конкатенацией, маршрутизацией... добавьте еще любые другие слова. Без примера кода это просто набор слов.
Т.к. сразу в новые или декомпозированные элементы нужно сразу тащить весь JS код.
Тоже неясно без кода ничего.
HTML совершенно отличный от QML - там нет биндингов и машины конечных состояний.
Биндинг это просто функция вместо значения которая вызывается когда надо получить значение, машины конечных состояний это функция-генератор которая нативно уже давно в любом JS рантайме поддерживается да и без нее это можно "за вечерок" реализовать если надо. QML использует JS движок из Chrome и заимствует огромное количество концепций из HTML, даже подмножество тегов HTML поддерживается в некоторых QML элементах. Поэтому "совершенно отличный" это преувеличение.
В моем бенчмарке исследуется вопрос производительности биндинга против присвоения через JS и C++
Я JS и С++ не сравнивал - не съезжайте с темы! Сравнивать бред - С++ будет на порядок быстрее. Сравнивается Binding и JS, а в ссылке про это всё есть:
It's slow. It delays errors that could be found at build time to run time, slowing down the development process. It overwrites any declarative binding that was in place. In most cases this is intended, but sometimes it can be unintentional. It interferes with tooling; Qt Quick Designer, for example, doesn't support JavaScript.
А функционал тоже выкидывался вместе с кодом?
Функционал полностью сохранялся и даже был лучше. Например выравнивание ширины ListView по макс элементу. У нас был деятель, который делал это через JS - уволили.
Тоже неясно без кода ничего.
NDA
Сравнивается Binding и JS
В моих тестах есть и такое сравнение и разница в скорости смешная.
а в ссылке про это всё есть
По ссылке рассматривается узкий пример инициализации значения и 'за' и 'против' применения onCompleted вместо определения поля с дефолтным значением. Про биндинги там вообще ни слова нет, и кто из нас съезжает с темы?
Например выравнивание ширины ListView по макс элементу.
А как стали делать `без JS`?
У нас был деятель, который делал это через JS - уволили.
Огласите пожалуйста название Вашей компании чтобы всем точно знать куда идти работать не стоит. Там где легко увольняют за одно решение.
NDA
Мы находимся на техническом ресурсе, и если Вы хотите кому-то что-то доказать то доказывать надо, не поверите, пруфами, т.е. кодом, тестами и бенчмарками. До тех пор пока Вы их не предоставили все Ваши слова не более чем трёп.
В моих тестах есть и такое сравнение и разница в скорости смешная.
В цикле до 1000 - это смешно!
По ссылке рассматривается
По ссылкАМ много примеров. Сравниваются подходы и принципы, а не примеры, которых может быть сотни.
Там где легко увольняют за одно решение.
Уволили не за это, а за многократное хамство и необучаемость как у вас.
А как стали делать
без JS
?
Через биндинги parent<->child элементов.
Трёп у вас: я предоставил документацию Qt, которая есть квинтэссенция опыта, который совпадает с моим.
Вот ещё хорошая документация по теме:
Qt best practices:
QML Application Structuring Approaches (some info is actual, some outdated)
А это ответ на ваш код:
QML-Coding-Guide - вообще хорошая дока по стилю QML
QML: отличие оператора ":" Qt.binding от Binding