I have a standard QProgressDialog with a cancel button. If/When the user clicks the cancel button, I don't want the dialog to immediately hide, instead I would prefer to disable the cancel button and perform some clean-up work, and then close the QProgressDialog once I'm sure this work is complete. How to I intercept the current function?
From the docs it seems like I should be overwriting:
PySide.QtGui.QProgressDialog.cancel()
Resets the progress dialog. PySide.QtGui.QProgressDialog.wasCanceled() becomes true until the progress dialog is reset. The progress dialog becomes hidden.
I've tried subclassing this method but it doesn't even seem to be called when I click the cancel button.
To disable the button of the dialog you have to get a reference to it. Since it is a basic QPushButton, you can use
findChild()
:Consider that disabling a button that would never get enabled is annoying from the UX point of view, so a better choice would be to not show it at all, and
setCancelButton()
explains how to do it:In python terms,
nullptr
meansNone
:Unfortunately, this won't prevent the user to cancel the dialog by closing it or by pressing Esc.
This is valid for any QDialog, and, to properly avoid that, subclassing is the better choice: you need to prevent rejecting the dialog (the Esc key) and the close event. While they have similar results, they are handled in different ways.
Overriding
reject()
(and doing nothing) prevents any action that would trigger a rejection (cancelling), including pressing Esc.Overriding the
closeEvent()
requires an extra step: you have to ensure that the event isspontaneous()
(triggered by the system - normally, the user presses the close button of the window), and eventually ignore that. This is necessary as you might need to callclose()
oraccept()
to actually close the dialog upon completing the process.Note that there is no direct way to know if the spontaneous close event is directly triggered by the user (trying to close the window), or the system (while shutting down).
Also note that if you do need to close the dialog programmatically, you either call
accept()
, or you call the base implementation, which allows you to get the proper return value from the dialog'sreject()
:Finally, if, for any reason, you still need the cancel button, you have to disconnect its signals.
In general, this might do the work:
But the above would disconnect any signal to any slot, and there are some cases for which this should be avoided.
We know from the sources that the
clicked
signal is actually connected to thecanceled()
slot, so a better solution would be to do the following instead:Since you may need to be notified about that in the parent/main class, a more appropriate solution would be to create a custom signal in the subclass used above: