当运行它的小部件(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内的小部件没有改变