如何将 QtConcurrent::run 函数(或类似函数)中的 progressText 传递给 QFutureWatcher?
Posted
技术标签:
【中文标题】如何将 QtConcurrent::run 函数(或类似函数)中的 progressText 传递给 QFutureWatcher?【英文标题】:How to communicate a progressText from a QtConcurrent::run function (or similar) to a QFutureWatcher? 【发布时间】:2014-05-02 22:45:00 【问题描述】:如果我使用QtConcurrent::run
启动某个异步执行函数,并使用QFutureWatcher
监视返回的未来,如果我可以在该异步执行函数中执行什么操作来传达一些进度文本,这将导致QFutureWatcher
发射其progressTextChanged
信号?
即我想做的是某事,比如:
void fn()
???->setProgressText("Starting);
...
???->setProgressText("halfway");
...
???->setProgressText("done!");
QFutureWatcher watcher;
connect(&watcher, SIGNAL(progressTextChanged(const QString&)), &someGuiThing, SLOT(updateProgress(const QString&)));
connect(&watcher, SIGNAL(finished(), &someGuiThing, SLOT(doStuff()));
QFuture<void> future=QConcurrent::run(fn);
watcher.setFuture(future);
然而,大问题,QtConcurrent::run documentation 明确说明
请注意,QtConcurrent::run() 返回的 QFuture 确实不支持 取消、暂停或进度报告。返回的 QFuture 可以 只用于查询运行/结束状态和返回 函数的值。
那么我能做的最简单的事情是什么,它可以让我在功能上与上述尝试做的事情相同?我必须放弃QtConcurrent::run
吗? QFuture
?两个都? (然后返回QThread
并排队连接?)
【问题讨论】:
【参考方案1】:QtConcurrent 函数(如QtConcurrent::mappedReduced()
)返回的QFuture 具有由progressValue()、progressMinimum()、progressMaximum() 和progressText() 函数提供的进度信息。不像QtConcurrent::run()
不会自动提供这样的东西。
QtConcurrent::run()
不像QtConcurrent::mappedReduced()
那样自动提供进度信息。但是您可以使用信号拥有自己的进度报告机制。我认为没有其他直接的方法。
【讨论】:
好的,但是我实际上在fn()
中调用了什么来获取要更新的进度信息?显然,它需要传递一些东西……但是什么?似乎有一个 QFutureInterfaceBase 具有进度信息设置方法,但 QFuture 实际上并没有继承它。嗯...显然下一步是查看QtConcurrent::mappedReduced()
的实现,看看它是如何实现的...
我认为使用信号报告进度是使用QtConcurrent::run()时最方便的方式。
是的,这就是我最终做的事情:使用带有 QueuedConnection 的 QMetaObject::invokeMethod 从并发函数中发送状态消息到监视其进度的插槽(实际上, BlockingQueuedConnection 似乎导致显示更流畅......我发送了很多消息)。更多关于qt-project.org/forums/viewthread/41012/#174738的上下文@【参考方案2】:
您仍然可以将QFutureWatcher
与QProgressDialog
一起使用,就像在我的示例中一样:
void hole_mark::get_frames_with_progress(const QString& movie, const QString& output)
Ptr<cv::VideoCapture> source = makePtr<VideoCapture>(movie.toUtf8().constData());
auto frames = (int)(source->get(CAP_PROP_FRAME_COUNT));
QProgressDialog dialog(tr("Importing frames: %1...").arg(frames), tr("Cancel"), 0, frames, this);
dialog.setWindowModality(Qt::WindowModal);
QFutureWatcher<void> futureWatcherProgress;
QFutureInterface<void> promise;
QFuture<void> future = promise.future();
promise.reportStarted();
QObject::connect(&futureWatcherProgress, SIGNAL(finished()), &dialog, SLOT(reset()));
QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcherProgress, SLOT(cancel()));
QObject::connect(&futureWatcherProgress, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));
QObject::connect(&futureWatcherProgress, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int)));
QObject::connect(&futureWatcherProgress, SIGNAL(progressTextChanged(const QString&)), &dialog, SLOT(setLabelText(const QString&)));
futureWatcherProgress.setFuture(future);
promise.setThreadPool(QThreadPool::globalInstance());
auto runnable = QRunnable::create([&, frames, source]()
promise.setProgressRange(0, frames);
promise.setProgressValue(0);
cv::Mat m;
int frame = 0;
while (!future.isCanceled())
*source >> m;
if (m.empty())
break;
promise.setProgressValueAndText(++frame, tr("Importing %1 frame from: %2...").arg(frame).arg(frames));
qDebug() << "frame: " << frame;
promise.reportFinished();
);
promise.setRunnable(runnable);
QThreadPool::globalInstance()->start(runnable);
// Display the dialog and start the event loop.
dialog.exec();
futureWatcherProgress.waitForFinished();
// Query the future to check if was canceled.
qDebug() << "Canceled?" << futureWatcherProgress.future().isCanceled();
【讨论】:
以上是关于如何将 QtConcurrent::run 函数(或类似函数)中的 progressText 传递给 QFutureWatcher?的主要内容,如果未能解决你的问题,请参考以下文章