Modal QProgressDialog::setValue() 导致嵌套事件循环崩溃

Modal QProgressDialog::setValue() causes crash by nested event loop

我刚刚编写了一些基于 QThread 的代码来执行大型计算。为了可视化进度,我需要打开一个 QProgressDialog。该对话框是应用程序模式的(使用 open()),因为我不想在计算期间修改主 window。线程发出各种信号,允许 GUI 和线程之间基于状态机的通信。

线程的工作对象发出的两个信号是 "Progress" 和 "Finished"。如果发出 "Progress",我将使用 setValue() 更新 QProgressDialog。如果发出 "Finished",对话框将被销毁。

计算结束时发生以下情况:

QProgressDialog 在 setValue() 中调用 processEvents() 破坏了我的架构。此外,我的编码约定禁止使用任何嵌套事件循环(如 exec() 等)。

我有两个问题:

  1. 为什么模态对话框需要嵌套事件循环?根据我的理解阻止父 windows' 输入似乎不需要这个。

  2. 是否可以在没有嵌套事件循环的情况下以模态方式使用 QProgressDialog?

你应该用deleteLater()来摧毁你的QProgressDialog。删除你的 QProgressDialog 对象的事件是在属于 QProgressDialog 对象本身的函数中处理的,这归结为在 c++ 成员函数中调用 delete this; 的合法性,你可以参考到 isocpp C++ FAQ 中的 this question 了解更多相关信息。大意是你要保证在自杀...

后不再访问该对象的任何成员

由于您无法在 Qt 的 QProgressDialog::setValue() 实现中保证这一点,因此 delete 类似 QProgressBar 的事件将在下次访问任何成员时愉快地调用 UB对象(在成员函数中获取时)。 deleteLater 专为解决此类问题而设计,因为延迟删除事件以特殊方式处理(它们不会被 QCoreApplication::processEvents() 拾取)。这意味着 QProgressDialog 对象将在 setValue returns 控制进入事件循环之后被销毁,而不是在执行 setValue...

的中间

在这种情况下始终使用 deleteLater。在事件中使用普通 delete 时,您必须确保在执行此对象的成员函数时不会处理此事件,并且不会因为从中发出信号而执行该事件这个对象(有一个直接的 signal/slot 连接)因为毕竟信号只是一个成员函数,其实现由 Qt 的 MOC 提供)...