1

PyQt4/5 on OSX El Capitan

I have a QMessageBox/QDialog which I want to be modal and want to block input from other GUI items while a process is running. The QDialog should provide the user the option to cancel the said process, but not allow him or her to do anything else with the GUI in the meantime.

Once the process is finished, it should close the QDialog and enable input to the main application again. Because things should happen in the background while the dialog is shown, I am not using exec_() to display the dialog.

Here is a simple example of my code:

self.openingDialog = QtWidgets.QMessageBox(self.main_window)
self.openingDialog.setText(_(u"Opening experiment. Please wait"))
self.openingDialog.setStandardButtons(QtWidgets.QMessageBox.Cancel)
self.openingDialog.reject.connect(<some_function>)
self.openingDialog.show()
self.openingDialog.raise_()

... [Perform process] ...

self.openingDialog.done(0)
self.openingDialog.close()
self.openingDialog.deleteLater()

Everything works nicely in the sense that the dialog box is shown, and that no interaction is possible with other GUI elements while it is displayed. However, when has process is finished, the dialog box is automatically closed but it is still not possible to interact with other GUI elements afterwards. The GUI does not respond to mouse clicks, menu items are not accessible, and you can't even click the close button, so the application needs to be Force Quit.

What am I doing wrong in automatically closing the QDialog?

Daniel Schreij
  • 773
  • 1
  • 10
  • 26
  • Does the dialog's cancel button work as expected? What happens if you get rid of the last four lines and just `hide()` the dialog instead? Also, have you confirmed that it's only the dialog that's cauising the problem? – ekhumoro May 04 '16 at 19:47
  • Yes, if I press cancel, then you gain back control over the interface. And when I phase out the dialog completely the app works as desired. hide() has the same effect as close() in that control is not returned the the GUI. – Daniel Schreij May 04 '16 at 20:16
  • Okay, so try replacing the last four lines with `reject()`. – ekhumoro May 04 '16 at 21:36
  • Have you tried using `QMessageBox::open()`? – jonspaceharper May 04 '16 at 23:44
  • [This question](http://stackoverflow.com/questions/10534628/a-blocking-but-non-modal-qdialog?rq=1) may be related, btw. – jonspaceharper May 04 '16 at 23:49
  • Thanks for thinking with me. @ekhumoro yes I have tried reject() but it did not have any effect. The interface still is not accessible after the dialog disappears. – Daniel Schreij May 05 '16 at 09:58
  • @JonHarper I haven't tried open() yet, but I will do that. I found the question you linked but it stated "I tried to solve this with a QMessageBox, but if I open it via exec(), it blocks the entire application, and if I use show(), the execution of the program goes on without waiting for user's reaction." and I do want the program to go on without the user's reaction while the answers are mainly focussed around the first option. – Daniel Schreij May 05 '16 at 10:00
  • @JonHarper, to my understanding, open() offers you the possibility to attach signals of the dialog to other slots. It doesn't offer the possibility to let the program terminate the dialog instead of the user and then stop blocking input from other widgets? – Daniel Schreij May 05 '16 at 10:21

1 Answers1

0

Ok, I have found sort of a workaround, although I don't think it is an elegant solution.

If I set the window modality to 'window modal' instead of 'application modal' by using:

self.openingDialog.setWindowModality(QtCore.Qt.WindowModal)

then the application regains focus and accessibility after the dialog has been closed by the program. Still this doesn't solve the problem when the dialog is an application modal, but for now this serves my needs.

Daniel Schreij
  • 773
  • 1
  • 10
  • 26