0

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

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

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

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

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

我有两个问题:

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

  2. 是否可以以模态方式使用 QProgressDialog 但没有嵌套事件循环?

4

1 回答 1

1

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

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

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

于 2017-09-14T22:43:52.533 回答