0

I just wrote some QThread based code that executes a big calculation. To visualize the progress I need to open a QProgressDialog. The dialog is application modal (using open()) since I do not want to allow modifications of the main window during calculation. The thread emits various signals that allow state machine based communication between GUI and thread.

Two of the signals emitted by the thread's worker object are "Progress" and "Finished". If "Progress" is emitted I am updating the QProgressDialog using setValue(). If "Finished" is emitted the dialog is destroyed.

The following happens at the end of calculation:

  • "Progress" event (100%) is emitted
  • "Finished" is emitted directly after
  • setValue(100) is called due to "Progress" event
  • Because the dialog is modal, setValue() calls processEvents()
  • processEvents() delivers the "Finished" event
  • The "Finished" event causes the Dialog to be destroyed in the middle of setValue() which causes a crash

QProgressDialog breaks my architecture by calling processEvents() in setValue(). Also my coding conventions forbid usage of any nested event loops (like in exec() etc.).

I have two questions:

  1. Why does a modal dialog require a nested event loop? From my undestanding blocking the parent windows' input seem not to require this.

  2. Is it possible to use QProgressDialog in a modal way but without a nested event loop?

Silicomancer
  • 8,604
  • 10
  • 63
  • 130

1 Answers1

1

you should use deleteLater() to destroy your QProgressDialog. The event that deletes your QProgressDialog object is handled within a function that belongs to the QProgressDialog object itself, this boils down to the legitimacy of calling delete this; within a c++ member function, you can refer to this question from the isocpp C++ FAQ for more information about this. The gist of it is that you should guarantee that you no longer access any member of the object after committing suicide...

since you cannot guarantee this in the Qt's QProgressDialog::setValue() implementation, an event that deletes the QProgressBar like that will happily invoke UB on the next access to any member of the object (when picked up within a member function). deleteLater was specifically designed to solve this kind of issue as deferred delete events are handled in a special manner (they are not picked up by QCoreApplication::processEvents()). This means that the QProgressDialog object will be destroyed after setValue returns control into the event loop and not in the middle of executing setValue...

Always use deleteLater in situations like this. When using plain delete within an event, you have to make sure that this event doesn't get handled while executing a member function of this object, and that it doesn't get executed as a result of emitting a signal from this object (with a direct signal/slot connection) since, after all, a signal is just a member function whose implementation is provided by Qt's MOC)...

Mike
  • 8,055
  • 1
  • 30
  • 44
  • setModal()/show() will not work here. I already use open(). QProgressDialog is special because it calls the event loop in setValue() anyway, no matter which kind of modality I use. – Silicomancer Sep 15 '17 at 07:57
  • @Silicomancer, Well then, the nested event loop has nothing to do with the crash you are describing. Anyway, I have answered your question about setting up a modal dialog without having a nested event loop (did I get your question right?), using `open()` seems to be another way too... – Mike Sep 15 '17 at 09:23
  • Sorry, Mike, but I think you didn't answer the question. I know how to set up a modal dialog without an event loop. My question is how to setup a modal *QProgressDialog* without event loop. But I guess that is not possible at all due to the special behavior of QProgressDialog::setValue(). Maybe deleteLater is a good workaround. I will give feedback after trying. – Silicomancer Sep 15 '17 at 09:40
  • I agree. And I will try. What a pitty that the Qt guys decided to still support bad designed applications by implementing nested loops. I think they should drop support for such broken archtitectures. If you remove/edit the modality part of your answer (that is not applicable to my case) I can accept your solution. – Silicomancer Sep 15 '17 at 09:55
  • @Silicomancer, I have removed the part talking about modality in my answer. But I think that you have to remove them from your question too. specifically your two questions at the end seem to conflict with the fact that you already are using `open()` and that you know how to setup a modal dialog without a nested event loop... – Mike Sep 15 '17 at 10:35