Russian Qt Forum
Ноябрь 23, 2024, 08:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Ожидание сигнала  (Прочитано 13421 раз)
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« : Ноябрь 02, 2018, 00:08 »

QEventLoop ожидает сигнал, но при этом все события обрабатываются.

Есть ли возможность сделать полностью синхронное выполнение - т.е. пока мой сигнал не пришёл, ничего не делам (никакие события не выполняются, гуи подвисло и т.д.)
« Последнее редактирование: Ноябрь 02, 2018, 00:37 от Azazello » Записан
zhbr
Гость
« Ответ #1 : Ноябрь 02, 2018, 06:33 »

не стартовать QEventLoop, а на ваш сигнал директом повесить слот, который запустит QEventLoop?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #2 : Ноябрь 02, 2018, 07:52 »

Не ясно, что конкретно требуется, но можно дождаться выполнение слота по месту вызова сигнала, если использовать Qt::BlockingQueuedConnection.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 02, 2018, 09:04 »

Есть ли возможность сделать полностью синхронное выполнение - т.е. пока мой сигнал не пришёл, ничего не делам (никакие события не выполняются, гуи подвисло и т.д.)
Нет, processEvents будет молотить все события очереди. Остается фильтровать отсекая нежелательные, лучшего я не нашел
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Ноябрь 02, 2018, 15:26 »

Пустить тред, в нем крутить эвентлуп из семи залуп, по сигналу выходить из него.
Ещё надо добавить ждун_условие и спать на нем в главном треде, после выхода из лупа будить.
Возможно что-то подобное есть в тест фреймворке.
А что мешает просто крутить луп, исключая юзер эвенты?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Ноябрь 02, 2018, 16:16 »

А что мешает просто крутить луп, исключая юзер эвенты?
Ничто не мешает, но будут обрабатываться и др события очереди, а это не все всегда хорошо/допустимо. Напр есть загрузка из 20 шагов, после каждого надо шлепнуть в UI текст "делаю то-то" и дождаться его отображения
Записан
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #6 : Ноябрь 05, 2018, 20:11 »

Пустить тред, в нем крутить эвентлуп из семи залуп, по сигналу выходить из него.
Ещё надо добавить ждун_условие и спать на нем в главном треде, после выхода из лупа будить.
Возможно что-то подобное есть в тест фреймворке.

Был бы не мой проект, так бы и сделал. Возможно, так и сделаю, когда надоест барахтаться.


Вообщем так и не поборол, что с одной стороны, что с другой (другую сторону придумайте сами)

Есть модель с асинхронной загрузкой данных. Rest.
Есть QGraphicsView(scene), который выступает view (в контексте MVC) для этой модели.

Смысл не отличается от обычной вью - скрол влево - данные подтянулись. Все ОК.

но при resizeEvent (могут же не все данные влазить во вью), когда требуется подкачка данных, начинается треш с вылетом. Для синхронной модели (те же данные) работает отлично.

Код fetchMore():
Код:
while (mRequestRows > 0) {
        qCDebug(candleModelDebug) << "Send rest request";
        RestEventLoop eventLoop;
        connect(&mRest,&Rest::stateChanged,&eventLoop,&RestEventLoop::finish);
        mRest.sendRequest();
        eventLoop.exec();

        qCDebug(candleModelDebug) << "Data loaded";

        QList<BaCandleData> buffer = mRest.candleData();
Куда концептуально идти -  не понятно.

RestEventLoop - обычный EventLoop просто со своим слотом
« Последнее редактирование: Ноябрь 05, 2018, 20:28 от Azazello » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Ноябрь 05, 2018, 22:04 »

Так а чо дебаггер говорит? Могу предположить, что внутри эвентлупа вьюга запрашивает fetchMore заново и стек кончается.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Ноябрь 05, 2018, 22:24 »

В resizeEvent вы только запускаете загрузку данных, но модель не обновляете и ничего не ждете, пусть рисуются только те объекты которые уже есть в модели. А на сигнал завершения загрузки вешаете слот модели, который обновит объекты и пошлет сигнал вьюшки на перерисовку.
Записан
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #9 : Ноябрь 05, 2018, 23:44 »

Так а чо дебаггер говорит? Могу предположить, что внутри эвентлупа вьюга запрашивает fetchMore заново и стек кончается.

Дебагер говорит о прохождении от функции маин (loop) до ексепшина. Т.е. проблема с сообщениями, какие-то друг другу противоречат. О переполнении стека говорить не приходится. Дебаг застрал после 1 часа втыкания- я понял  - застряну в дебаге надолго и даже знание проблемы не даст ничего.

В resizeEvent вы только запускаете загрузку данных, но модель не обновляете и ничего не ждете, пусть рисуются только те объекты которые уже есть в модели. А на сигнал завершения загрузки вешаете слот модели, который обновит объекты и пошлет сигнал вьюшки на перерисовку.

Я понял вашу мысль. Вы просто предлагаете разделить данные во времени (по сути). Но это ничего не даст, пользователь просто может залипнуть на ресайзе мышкой, и тогда ситуация ничем не будет отличаться от существующей.

Хотя попробую! Да, а нам то как раз и зависимость сигналов то не нужна.
« Последнее редактирование: Ноябрь 05, 2018, 23:48 от Azazello » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Ноябрь 05, 2018, 23:49 »

Ну old прав - обычно при запросе fetch more взводится флажок "фетчим" чтобы не перечерчивать и когда данные появляются, флажок сбрасывается и они вставляются в модель.
Записан
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #11 : Ноябрь 06, 2018, 11:44 »

Ну old прав - обычно при запросе fetch more взводится флажок "фетчим" чтобы не перечерчивать и когда данные появляются, флажок сбрасывается и они вставляются в модель.

Это сработает, когда ресайз охватывает один фетч. А если несколько. Да, можно установить размер пакета, который перекрывает заранее окно. Но не в моем случае. У меня есть масштабирование, и при очень мелком масштабе при ресайзе может быть вызвано десятки фетчей.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Ноябрь 06, 2018, 12:51 »

Это сработает, когда ресайз охватывает один фетч. А если несколько. Да, можно установить размер пакета, который перекрывает заранее окно. Но не в моем случае. У меня есть масштабирование, и при очень мелком масштабе при ресайзе может быть вызвано десятки фетчей.
Так ставьте запросы в очередь, по мере подгрузки данных сцена будет обновляться.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Ноябрь 06, 2018, 13:45 »

Есть модель с асинхронной загрузкой данных. Rest.
...
Код fetchMore():
Ну если "асинхронно", то надо полагать что RestEventLoop выполняется в др нитке (не главной). Это нормально, но трогать сцену напрямую эта нитка не должна. Нужно через QueuedConnection

но при resizeEvent (могут же не все данные влазить во вью), когда требуется подкачка данных, начинается треш с вылетом.
resizeEvent - одно событие, прием новых данных сцены - другое, пересекаться они не должны. Юзер залип - ну новые данные не отобразятся (пока не отлипнет), это не катастрофа


Записан
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #14 : Ноябрь 06, 2018, 14:12 »

resizeEvent - одно событие, прием новых данных сцены - другое, пересекаться они не должны. Юзер залип - ну новые данные не отобразятся (пока не отлипнет), это не катастрофа

Ладно. Реально я это не поборол, просто отодвинул.
Подытожу.
Условие:
Программа валится, когда происходит Resize вью и получение данных (fetchMore + EventLoop).
События эти во времени нельзя разделить, т.к. это получение данных у нас асинхронно - мы не знаем когда данные прийдут, а могут прийти когда мы делаем ресайз, повторно ресайз (данные с первого), ковыряемся в носу и т.д.

Решение. Пока такое:
Очередь запросов (просто их количество). И если я в своем вью для асинхонной модели могу при fetchMore проверить, что у нас в очереди для загрузки есть данные (т.е. не нужно делать fetchMore), и не выполнять запрос, то для стандартной вьюхи это не возможно, и любое fetchMore будет скачивать данные, понятно почему, rowCount изменится позже. Не очень критично, чтобы сейчас переписывать стандартный вью.

Вывод: Дизайн MVC (в Qt) не предназначен для асинхронной загрузки данных.


Ну, может псевдокод для понимания.
Код:

void GraphicsView::checkNeedData()
{
    int fetchCount = requestVisibleData();
    int needRowCount = fetchCount + model->rowCount();
    if (needRowCount > model->[b]requestRowCount[/b]()) {
        qCDebug(graphicsViewDebug) << "Data size: " << scene()->model()->rowCount();
        int fetchedCount = fetchData(fetchCount);
        qCDebug(graphicsViewDebug) << "Send request fetched data" << fetchedCount;

    }

void CaModel::fetchMore(const QModelIndex &)
{  
    .....

    if (mRequestRows == 0) {
        mRequestRows = mRest.limit();
        mRest.sendRequest();
    } else { //if data in progress
        mRequestRows += mRest.limit();
    }
}

void CaModel::finishFetch(Ba::ReplyNetworkState state)
{
    qCDebug(candleModelDebug) << "Data loaded";

    QList<BaCandleData> buffer = mRest.candleData();
    mRequestRows -= buffer.size();

    if (buffer.size() == 0)
        return;

    beginInsertRows(QModelIndex(),rowCount(),rowCount() + buffer.size() - 1);
    mData.append(std::move(buffer));
    endInsertRows();

    if (mRequestRows > 0)
        mRest.sendRequest();
}



« Последнее редактирование: Ноябрь 06, 2018, 14:38 от Azazello » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.123 секунд. Запросов: 22.