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

标签 c++ qt qeventloop queued-connection qprogressdialog

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

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

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

  • 发出“进度”事件 (100%)
  • “Finished”在
  • 之后直接发出
  • setValue(100) 由于“Progress”事件被调用
  • 因为对话框是模态的,所以 setValue() 调用 processEvents()
  • processEvents() 传递“完成”事件
  • “完成”事件导致对话框在中间被销毁 导致崩溃的 setValue()

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

我有两个问题:

  1. 为什么模态对话框需要嵌套事件循环?从我的理解来看,阻止父窗口的输入似乎不需要这个。

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

最佳答案

你应该使用deleteLater()摧毁你的QProgressDialog .删除您的 QProgressDialog 的事件对象在属于 QProgressDialog 的函数中处理对象本身,这归结为调用 delete this; 的合法性在 c++ 成员函数中,您可以引用 this question从 isocpp C++ FAQ 获取更多相关信息。其要点是你应该保证在自杀之后不再访问该对象的任何成员......

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

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

关于c++ - Modal QProgressDialog::setValue() 导致嵌套事件循环崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46229002/

相关文章:

c++ - 在插槽中调用 QDialog::exec 是否会阻塞主事件循环?

c++ - 解析 C++ 字符串

c++ - 使用 Qt 在 Mac OS 上开始开发

c++ - 如何修复 "GStreamer-CRITICAL **: gst_sample_get_buffer: assertion ' GST_IS_SAMPLE(示例 )' failed"

linux - 如果硬件支持,QNativeGesture 是否可以在 Linux/Windows 上运行?

qt - QThread/QDialog 的竞争条件

c++ - 在 if() 中比较 LPCWSTR

C++ 复制赋值运算符问题

qt - 如何使用样式表获取 QWidget 的括号样式边框?

c++ - QEventLoop 处理所有事件