When using QtConcurrent::run
to run code in the background from a UI the
QFuture::then(QObject *context, Function &&function)
can be used to update the UI because you can pass the window object as context to make function
execute on the GUI thread. This is very convenient however there is one problem. When the window is closed and it is deallocated before the background task completes the program will crash when the task completes because the context
passed to then
is no longer valid.
Is there an easy way to prevent this problem? I know a QFutureWatcher
can be used but that object would need to be added to the window class and one would be needed for every asynchronous task the window can execute which is cumbersome.
One simple option would be to use a QPointer
to track/monitor the QWidget
of interest. A copy of the QPointer
can be captured by whatever lambdas or functors are used by QtConcurrent::run
or QFuture::then
.
/*
* Set up the QWidget that we need to monitor.
*/
auto w = std::make_unique<QLabel>("Working...");
w->show();
/*
* Create a QPointer that that we can use to check the validity of 'w'.
*/
auto qp = QPointer<QWidget>(w.get());
/*
* We can now bind qp into any lambdas.
*/
auto f = QtConcurrent::run(
[]
{
/* Time consuming stuff goes here. */
})
.then(
qApp,
[qp]
{
if (qp) {
/*
* qp reports that 'w' is still valid so do whatever we
* need to do with it.
*/
qp.data()->setText("Done");
} else {
/*
* 'w' is no longer valid.
*/
}
});
[Note: the above is untested as I don't have Qt6
on the box I'm working on right now.]