Russian Qt Forum

Qt => Qt Quick => Тема начата: navrocky от Декабрь 27, 2015, 19:15



Название: QML & JS & C++. Асинхронные цепочки кода. Боль. Много боли.
Отправлено: navrocky от Декабрь 27, 2015, 19:15
У меня складывается ощущение что я что-то делаю не так.

У меня есть модель на C++ от QObject, у неё есть метод update() и свойство updating.

Собственно мне из QML кода надо вызвать update() при необходимости и дождаться когда завершится этот самый update() по сигналу от свойства updating. Казалось бы, должен быть какой-то простой JS/QML что тут может проще.

Хотелось сперва написать как-то в духе JS
Код:
myObject.update({
    afterUpdate: function () {
        doSomething();
    }
})

Но я не придумал как звать JS лямбду из C++ кода. Дока довольно куцая. Да и если будет несколько параллельных вызовов update() к одному объекту, такая конструкция не прокатит.

Второе можно было бы написать такой код

Код:
var modelObject = model.item // this is my QObject successor with update() method
var context = {}
context.onUpdatingChanged = function () {
    if (modelObject.updating)
        return
    
    modelObject.updatingChanged.disconnect(context.onUpdatingChanged)
    
    doSomethingAfterUpdate();
};

modelObject.updatingChanged.connect(afterUpdate)
if (!modelObject.updating)
    modelObject.update()

Здесь я проверяю, что update еще не идет, запускаю его, отслеживаю состояния завершения update, отсоединяюсь от сигнала и продолжаю выполнять код после update.

Но облом поджидал в методе disconnect. Он работает только для свободных JS функций. Для лямбд выдает ошибку. Хотя connect для лямбды нормально отрабатывает.

Третья попытка сделать специальный QML класс ModelUpdater:
Код:
import QtQuick 2.5

/* model must conforms such interface

  function update()
  property updating: bool
  signal updateError

  */

QtObject {

    property var model
    property var continuation

    id: root

    function update(needUpdate) {
        if (root.model.updating || needUpdate) {
            root.model.updatingChanged.connect(root.updateChanged)
            if (!root.model.updating)
                root.model.update()
        } else
            root.continuation()
    }

    function updateChanged(updating) {
        if (updating)
            return
        root.model.updatingChanged.disconnect(root.updateChanged)
        root.continuation()
    }
}

В котором есть отдельная свободная функция updateChanged, которую можно подключать и отключать от сигнала без проблем. Но вот динамическое использование этого объекта опять
вылилось в очередную боль:

Global.js
Код:
var modelUpdaterComponent = null;

function updateModel(model, needUpdate, continuation) {
    
    if (!modelUpdaterComponent) {
        modelUpdaterComponent = Qt.createComponent("qrc:/ModelUpdater.qml");
    }
    
    var updater = modelUpdaterComponent.createObject(null, {model: model, continuation: continuation});
    updater.update(needUpdate)
}

Что здесь не так? Я не мог понять, почему этот код с расставленными точками останова в отладчике работает, а при обычном исполнении не работает. Я совсем забыл, что динамически созданный объект updater еще надо удерживать, иначе его зачищает GC так и не дав исполниться до конца.

Арггххх. Тоесть надо еще городить код обвязки который будет удерживать этот объект!!!

Почему так всё сложно то выходит. Где я мог накосячить в своих рассуждениях, как это все можно проще организовать?

В общем я продолжаю дальше набрасывать, пока безрезультатно.

Спасибо осилившим дочитать этот поток сознания  ;D


Название: Re: QML & JS & C++. Асинхронные цепочки кода. Боль. Много боли.
Отправлено: BuRn от Январь 20, 2016, 23:20
Не пойму, а почему бы во втором варианте, вместо дисконект, не кинуть сигнал, о том что якобы все ок, поймать сигнал и сделать дисконект там, не прокатывает так ? Ну или на крайняк можно всунуть таймер на 10мс и в триггеред отключить слот от сигнала


Название: Re: QML & JS & C++. Асинхронные цепочки кода. Боль. Много боли.
Отправлено: navrocky от Январь 22, 2016, 15:36
Не пойму, а почему бы во втором варианте, вместо дисконект, не кинуть сигнал, о том что якобы все ок, поймать сигнал и сделать дисконект там, не прокатывает так ? Ну или на крайняк можно всунуть таймер на 10мс и в триггеред отключить слот от сигнала

Проблема в том, что лямбду в JS можно зацепить за слот, а вот отцепить уже нельзя - выдает ошибку. Приходится городить огород.