Я использую QtConcurrent для обработки тяжелых фоновых изображений, и я хочу отображать изображение, пока его части постепенно обновляются. Каждая строка изображения вычисляется отдельно и передается функтору.
Затем для вычисления полного изображения у меня есть последовательность элементов, которые я передаю в QtConcurrent, и каждая строка излучает сигнал, когда она завершает вычисление
Вот экземпляр класса Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Вот слот для отчета о прогрессе:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Теперь об использовании:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
Все сигналы испускаются, но слот onProgressUpdate вызывается только тогда, когда Qtconcurrent :: mapped выполняется со всеми элементами в последовательности.
При выполнении он имеет огромную задержку во время обработки последовательности, а затем все слоты выполняются последовательно после этого.
Я пробовал все типы подключения сигналов / слотов, и ни один из них не изменил это поведение.
Есть подсказка?
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++ РЕДАКТИРОВАТЬ после предложения Shf +++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++
Вызов выполнялся до сих пор в основном (gui) потоке. Я изменил звонок на:
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Поскольку _computeTreeForFrame
теперь выполняется в другом потоке, я изменил вызов QtConcurrent :: mapped на:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
Это приводит к тому же поведению, что и раньше.
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++ РЕДАКТИРОВАТЬ после предложения Марека Р. ++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++
Итак, я провел тесты, и вот что я заметил:
QtConcurrent :: map:
- Не подает сигнал
resultReadyAt(int)
QtConcurrent :: mapped
- Выдает
resultReadyAt(int)
только после завершения
Не имеет значения, выполняется ли вызов функции карты в отдельном потоке, наблюдается такое же поведение.
Я также попробовал сигнал progressValueChanged(int)
, как предлагает пример Qt progressDialog. Сигнал progressValueChanged(int)
излучается только для 2 строк изображения (первой и последней). Это действительно странно, поскольку в примере диалога выполнения Qt он запускается плавно.
Я немного изменил пример Qt, чтобы запустить функцию карты в другом потоке, а не в основном потоке, и в этом случае она по-прежнему работает хорошо.
Проблема должна возникать откуда-то еще.
Может быть, цикл событий GUI делает то, чего я не ожидаю? Понятия не имею, что именно.
Сейчас я попробую QtConcurrent :: mappedReduced и сообщу о результатах :-)
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++ EDIT после попытки QtConcurrent :: mappedReduced +++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++
Он не работает и вызывает функцию «уменьшить» ТОЛЬКО, когда функция «карта» выполнена. Другими словами, он делает то же самое, что и предыдущий механизм сигналов / слотов.
Сейчас у меня мало возможностей
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++ РЕДАКТИРОВАТЬ Я вернулся к решению так же близко, как диалоговое окно прогресса Qt пример +++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++
Что-то должно быть не так, если я не могу добиться того же поведения, что и в примере Qt.
Вот код сейчас:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
Вызов computeTreeForFrame ...
...
_worker->computeTreeForFrame();
...
Этот вызов выполняется в слоте.
Он излучает сигналы для строки 0 и для последней строки, как было сказано ранее, но не испускает ничего другого.
Разве это не должно делать ТОЧНО то, что делает пример Qt?