如何关闭Qt对话框时终止异步功能

问题描述 投票:2回答:2

背景

我有一个对话框,该对话框在初始化时会执行耗时的操作。我将此操作包装到一个异步函数中,以免冻结GUI。

示例

想象一个对话框/窗口小部件,它显示了从远程服务器异步获取的当前天气:

Dialog::Dialog()
{
    auto label = new QLabel(this);
    QtConcurrent::run([=]() {
        const int temperature = getWeather(); // Time-consuming function
        label->setText(temperature);
    });
    // The rest code, layouts initialization, etc.
}

问题

如果此对话框/小部件在异步操作完成之前关闭,则label->setText()部分显然会导致崩溃,因为到那时该小部件对象将不存在。

问题

解决这种情况的正确方法是什么?可能,我应该使用其他方式代替QtConcurrent(例如,QThread),以便在关闭对话框时正确取消异步功能。

注意

请注意,实际代码与读取一堆文件有关,not与网络有关,这就是为什么不使用异步QNetworkRequest接口的原因。

qt asynchronous qwidget qthread qtconcurrent
2个回答
3
投票
// global or class member
QFutureWatcher<int> g_watcher;

Dialog::Dialog()
{
    connect(&g_watcher, &QFutureWatcher<int>::finished, this, &Dialog::handleFinished);

    QFuture<int> future = QtConcurrent::run([]() -> int
    {
        int temperature = getWeather(); // Time-consuming function

        return temperature;
    });

    g_watcher.setFuture(future);
}

void Dialog::handleFinished()
{
    // will never crash because will not be called when Dialog destroyed
    ui->label->setText(QString::number(g_watcher.result()));
}

ps.s。至于取消异步操作,无法通过QtConcurrentQThread方法正确取消它。

QThread::terminate()方法,但来自文档:

...警告:此功能很危险,不建议使用。的线程可以在其代码路径中的任何位置终止...

因此,您必须在getWeather()函数内部实现一些“取消”标志,或按照上面的描述进行操作。


0
投票

QtConcurrent::run()将返回一个QFuture<T>。您应该可以在其上调用QFuture::waitForFinished

另一件事是,您不应被允许从另一个线程调用QLabel::setText,而应使用QMetaObject::invokeMethod或发出信号。

© www.soinside.com 2019 - 2024. All rights reserved.