当运行long-for循环的小部件(QDialog)在没有多线程的情况下关闭时,我如何停止它

How can I stop a long for loop when the widget (QDialog) running it is closed without multithreading?

本文关键字:情况下 多线程 何停止 小部 循环 long-for 运行 QDialog      更新时间:2023-10-16

我在QDialog中有一个相当长的foreach循环。基本上看起来是这样的:

foreach (xxx, xxx) {
    ... doSomeStuff ...
    QApplication::processEvents();
    if (m_cancelMapLoading) {
        break;
    }
}

通过单击"取消"按钮将m_cancelMapLoading设置为true。QApplication::processEvents();使这成为可能。

这可以很好地工作,但如果只要foreach循环仍在运行,对话框就会关闭,它就会继续运行。我试图在关闭对话框的每个函数中将m_cancelMapLoading设置为true,但这无济于事。

我还尝试测试m_cancelMapLoading是否为true,以及isVisible()是否为true。这实际上停止了对话框,但它在没有GUI元素的情况下立即重新打开对话框

不幸的是,QtConcurrent::run等不能用于该函数,因为foreach循环操作的数据结构不是线程安全的。

有什么方便的方法可以解决这个问题吗?

您可以在此处使用QTimer和Qt的父子结构。超时值为零的QTimer在Qt 中具有特殊意义

作为一种特殊情况,超时为0的QTimer将尽快超时因为窗口系统的事件队列中的所有事件已处理。这可以用来做繁重的工作,同时提供快速用户界面:

所以你可以做一些类似的事情

void Dialog::beginDoingStuff()
{
    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(processData());
    m_timer->start(0);
}
void Dialog::processData()
{
    // Perform one cycle of your process here
}

这将在与对话框其余部分相同的线程中执行processData()函数,当对话框因关闭而被破坏时,计时器将被删除(因为它的父级是对话框),这意味着处理将停止。

从繁重的处理中卸载GUI的一个好而简单的方法是将其分配给另一个线程或QtConcurrent。

然后,您可以轮询"should-I-terminate-yet?"变量,或者在不再需要时手动终止线程。

我强烈建议并行处理,因为它提供了更好的控制,而不是像"DoEvents"那样清空队列。

我们实际上通过将对话框的完成信号连接到取消按钮的点击槽来解决了这个问题。这实际上在所有情况下都会停止循环。

我们还引入了通过QTimer启动函数(为了更好地实现,不阻塞函数启动的地方),但这并不能停止循环(也许是因为我们不会在对话框关闭时破坏它)。

感谢所有帮助:-)

相关文章: