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

时间:2017-09-14 22:14:46

标签: c++ qt qeventloop queued-connection qprogressdialog

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

线程工作者对象发出的两个信号是" Progress"和"完成"。如果" Progress"发出我正在使用setValue()更新QProgressDialog。如果"完成"发出对话框被破坏。

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

  • "进度"事件(100%)被发出
  • "成品"在
  • 之后直接发出
  • 由于" Progress"而调用了setValue(100)。事件
  • 因为对话框是模态的,所以setValue()调用processEvents()
  • processEvents()提供"已完成"事件
  • "已完成" event导致Dialog在中间被销毁 setValue()导致崩溃

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

我有两个问题:

  1. 为什么模态对话框需要嵌套的事件循环?从我未完成的阻止父窗口'输入似乎不需要这个。

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

1 个答案:

答案 0 :(得分:1)

您应该使用deleteLater()来销毁QProgressDialog。删除QProgressDialog对象的事件是在属于QProgressDialog对象本身的函数内处理的,这归结为在c ++成员函数中调用delete this;的合法性,您可以参考有关此内容的详细信息,请参阅isocpp C ++ FAQ中的this question。它的要点是你应该保证在自杀后不再访问该对象的任何成员 ...

因为你无法在Qt的QProgressDialog::setValue()实现中保证这一点,delete QProgressBar这样的事件会在下次访问对象的任何成员时愉快地调用UB(在成员函数中获取时)。 deleteLater专门用于解决此类问题,因为延迟删除事件是以特殊方式处理的(QCoreApplication::processEvents()不会选择它们)。这意味着QProgressDialog对象将在setValue将控制权返回到事件循环而不是执行setValue ...

之后被销毁。

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