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

Posted

技术标签:

【中文标题】当运行它的小部件(QDialog)在没有多线程的情况下关闭时,如何停止长 for 循环?【英文标题】:How can I stop a long for loop when the widget (QDialog) running it is closed without multithreading? 【发布时间】:2014-11-03 21:28:22 【问题描述】:

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

foreach (xxx, xxx) 
    ... doSomeStuff ...
    QApplication::processEvents();

    if (m_cancelMapLoading) 
        break;
    

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

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

我还尝试不仅测试 m_cancelMapLoading 是否为真,还尝试测试 isVisible()。这实际上停止了对话框,但它会立即重新打开它,但其中没有 GUI 元素。

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

有没有方便的方法来解决这个问题?

【问题讨论】:

你试过在类析构函数中将变量 m_cancelMapLoading 赋值为 true 吗? 这样做,循环继续运行。 手动推进事件循环会导致各种可怕的后果。尝试将检查 m_cancelMapLoading 作为 foreach 循环中的第一件事,看看是否“修复”了问题。 【参考方案1】:

您可以在这里使用QTimer 和Qt 的父子结构来发挥您的优势。超时值为0的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() 函数,并且当对话框被关闭而销毁时,计时器将被删除(因为它的父级是对话框),这意味着处理将停下来。

【讨论】:

感谢您提供此信息!我会试试这个!【参考方案2】:

从繁重的处理中卸载 GUI 的一种非常简单的好方法是将其分配给另一个 thread 或 QtConcurrent。

然后,您可以轮询一个 “我应该终止吗?” 变量,或者在不再需要线程时手动终止它。

我强烈推荐并行处理,因为它提供了更好的控制,而不是执行类似“DoEvents”的队列清空。

【讨论】:

我试图通过 QtConcurrent 来做,但是这个函数操作的数据结构并不打算被多线程使用。这确实导致了很多现在可能无法解决的问题:-( 为了将工作负载转移到那里,需要线程安全。我不确定是否要将此作为答案,无论如何您应该编辑您的问题以澄清它。【参考方案3】:

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

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

感谢所有帮助:-)

【讨论】:

以上是关于当运行它的小部件(QDialog)在没有多线程的情况下关闭时,如何停止长 for 循环?的主要内容,如果未能解决你的问题,请参考以下文章

QWidget QMainWindow QDialog 之间的区别

当setState Flutter时,PageViewer内的小部件没有改变

Pyqt QMdiSubWindow 使用可变数量的小部件调整大小

为啥当主应用停止时我的小部件广播接收器服务停止

java线程的小问题与回答

如何在点击外部关闭 QDialog 并在点击子小部件时关闭?