Вопрос чайника по Qt Quick



  • Извините за глупый вопрос, я только осваиваю Qt Quick. Доки великолепные, но ответов на глупые вопросы в них нет :-) Пока не взберешься хоть чуть-чуть по кривой обучения...

    В QML я могу написать:

    textEdit1.text: textEdit2.text
    textEdit2.text: textEdit1.text
    

    И вот она, особая уличная магия. Как движку Qt Quick это удалось? По логике, единственное, что нужно знать - соответствие имени свойства (text) и имени сигнала об изменении этого свойства (textChanged). Зная только это, движок как бы неявно добавляет:

    textEdit2.onTextChanged: textEdit1.text = textEdit2.text
    textEdit1.onTextChanged: textEdit2.text = textEdit1.text
    

    и вуаля.

    Теперь я хочу сделать такой же двусторонний байндинг, но чтобы вместо textEdit2 был объект C++.

    class TextObject: public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged)
        ...
    };
    ...
    TextObject textObject2;
    engine.rootContext()->setContextProperty("textObject2", &textObject2);
    

    По принципу наименьшего удивления руки сами пишут:

    textEdit1.text: textObject2.text
    textObject2.text: textEdit1.text
    

    А шо? Ведь и тут Qt известна связь между свойством text и сигналом textChanged объекта textObject2.

    Фигушки. Чтобы двусторонний байндинг заработал пришлось расписать аж так:

    textEdit1.text: textObject2.text
    textEdit1.onTextChanged: textObject2.text = textEdit1.text
    Connections
    {
        target: textObject2
        onTextChanged: mainForm.textEdit1.text = textObject2.text
    }
    

    Просто не верится, что в таком умном Qt Quick требуется такое непотребство.

    Вопрос: а как правильно?



  • у меня тоже вопрос чайника:
    а можно привести полные исходные тексты или хотя бы qml, ибо не могу однозначно понять каким образом приведенные строки кода тестируются?
    textEdit1.text: textObject2.text
    textObject2.text: textEdit1.text

    http://pastebin.com/fLqtaQiD - у меня вот так работает, правда через qmlRegisterType.



  • Спасибо за ответ!

    а можно привести полные исходные тексты или хотя бы qml, ибо не могу однозначно понять каким образом приведенные строки кода тестируются?

    А они никак и не тестируются, так как это не работает. Ошибка Cannot assign to non-existent property "textObject2". Приведенное – это то, что казалось логичным по аналогии с парой textEdit-ов.

    у меня вот так работает, правда через qmlRegisterType

    А у меня не работает =/ Добавил к вашему примеру кнопку, два слота и отладочного вывода: textobject.h, main.qml, main.cpp не менял.

    Во-первых, textObject2 в main.cpp и textObject2 в main.xml - это два разных объекта, второй создается движком. Можно вообразить ситуацию, когда это даже хорошо, но в моем случае нужно привязаться к уже созданному объекту.
    Во-вторых, плохо то, что сначала значение переносится из QML в C++, а не наоборот.
    И, наконец, байндинг все-таки односторонний: когда данные изменяются в C++, textEdit1 не обновляется (для этого слот changeValueViaCPP() и кнопка).

    Еще вариант подсказала эта статья.
    Двустороннюю связь можно создать и так:

    textEdit1.text: textObject2.text
    Binding {  
        target: textObject2
        property: "text"  
        value: mainForm.textEdit1.text 
    }  
    

    ИМХО, даже вариант с Connections лучше.
    А хочется чего-то вроде BindingMode.TwoWay из WPF.



  • textObject2 в main.cpp конечно не тот что qml, это я не стер его в первый раз пока эксперименты делал
    https://yadi.sk/d/IDzLcmdaiXJc6 - ссылка на архив с проектом со всякими экспериментами, главное не запутаться в похожих именах



  • Спасибо за участие. Ваше предложение насчет создания объекта QML-движком из всех зол кажется наименьшим. Пока замечены такие gotchas:

    1. Нужно следить, чтобы в QML TextObject {} текстуально шел ниже TextEdit {}, иначе первое движение значения будет неверным.
    2. Чтобы потом созданнй TextObject выцарапать, ему нужно задать objectName.
    3. Довольно кучерявый способ выцарапывания:
    TextObject *obj = engine.rootObjects().first()->findChild<TextObject*>("objectName from QML");
    
    1. В конструктоор TextObject не передашь параметров.
    2. Можно случайно насоздавать несколько TextObject-ов там где по замыслу он должен быть один (в случае setContextProperty() без qmlRegisterType() это было бы невозможно).
    3. TextObject насмерть привяан к GUI thread.

    Но все это мелочи, так как Binding и Connections совсем уже костыли.

    Да, разбаловали всякие там WPF, Backbone, да AngularJS.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.