Modal QProgressDialog::setValue() 导致嵌套事件循环崩溃
Modal QProgressDialog::setValue() causes crash by nested event loop
我刚刚编写了一些基于 QThread 的代码来执行大型计算。为了可视化进度,我需要打开一个 QProgressDialog。该对话框是应用程序模式的(使用 open()),因为我不想在计算期间修改主 window。线程发出各种信号,允许 GUI 和线程之间基于状态机的通信。
线程的工作对象发出的两个信号是 "Progress" 和 "Finished"。如果发出 "Progress",我将使用 setValue() 更新 QProgressDialog。如果发出 "Finished",对话框将被销毁。
计算结束时发生以下情况:
- "Progress" 事件 (100%) 已发出
- "Finished" 直接在
之后发出
- setValue(100) 由于 "Progress" 事件被调用
- 因为对话框是模态的,所以 setValue() 调用 processEvents()
- processEvents() 传送 "Finished" 事件
- "Finished"事件导致Dialog中途销毁
导致崩溃的 setValue()
QProgressDialog 在 setValue() 中调用 processEvents() 破坏了我的架构。此外,我的编码约定禁止使用任何嵌套事件循环(如 exec() 等)。
我有两个问题:
为什么模态对话框需要嵌套事件循环?根据我的理解阻止父 windows' 输入似乎不需要这个。
是否可以在没有嵌套事件循环的情况下以模态方式使用 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 提供)...
我刚刚编写了一些基于 QThread 的代码来执行大型计算。为了可视化进度,我需要打开一个 QProgressDialog。该对话框是应用程序模式的(使用 open()),因为我不想在计算期间修改主 window。线程发出各种信号,允许 GUI 和线程之间基于状态机的通信。
线程的工作对象发出的两个信号是 "Progress" 和 "Finished"。如果发出 "Progress",我将使用 setValue() 更新 QProgressDialog。如果发出 "Finished",对话框将被销毁。
计算结束时发生以下情况:
- "Progress" 事件 (100%) 已发出
- "Finished" 直接在 之后发出
- setValue(100) 由于 "Progress" 事件被调用
- 因为对话框是模态的,所以 setValue() 调用 processEvents()
- processEvents() 传送 "Finished" 事件
- "Finished"事件导致Dialog中途销毁 导致崩溃的 setValue()
QProgressDialog 在 setValue() 中调用 processEvents() 破坏了我的架构。此外,我的编码约定禁止使用任何嵌套事件循环(如 exec() 等)。
我有两个问题:
为什么模态对话框需要嵌套事件循环?根据我的理解阻止父 windows' 输入似乎不需要这个。
是否可以在没有嵌套事件循环的情况下以模态方式使用 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 提供)...