[PyQt] why do closeEvent and destroyed slot not get called on accepting PyQt4 QDialog?

Hans-Peter Jansen hpj at urpla.net
Thu Apr 7 16:44:22 BST 2011

On Thursday 07 April 2011, 17:27:15 Rui DaCosta wrote:
> Firstly thanks again for your reply,
> In the original code, from where this simplification is based, I have
> cleanup code on both closeEvent and destroyed, but...
> that's just the problem, the closeEvent isn't getting fired (unless I
> manually call close) - except when the window is closed from the
> close box.
> I was expecting that from the docs for done(), I would not have to on
> done(), ie. is this a bug? or are the docs incorrect?
> And separately,  destroyed is a signal according to the docs
> http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qobject.ht
> but I cannot get it to fire for QDialog, no matter what I do,
> including manually calling destroy().
> The object appears deleted when inspected with sip.isdeleted, even
> before the destroy() - so if that is the case, why does it not raise
> a destroyed signal?

Well, looks like this is an issue in Heisenbergs uncertainty principle
domain ;-)

It's simply the GC, that's in the way. If you anchor the connect 
somewhere else, the destroyed signal "gets though". If your real dialog
has a parent, you might get away with anchoring the connect there.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

def pr(arg):
    sys.stdout.write(arg + "\n")

class Dialog(QDialog):
    def __init__(self):
        QDialog.__init__(self, None, Qt.WindowFlags(Qt.WA_DeleteOnClose))
        self.button_box = QDialogButtonBox(self)
        layout = QVBoxLayout()

    def on_destroyed(self, *args):
        pr("destroying dialog")

    def on_accept(self):

    def closeEvent(self, event):
        return QDialog.closeEvent(self, event)

app = QApplication([])
widget = Dialog()
widget.destroyed.connect(lambda: pr("destroyed"))
result = widget.exec_()
del widget
print("result: %s" % result)

> ________________________________
> From: Demetrius Cassidy <dcassidy36 at gmail.com>
> To: Rui DaCosta <ruidc at yahoo.com>
> Cc: pyqt at riverbankcomputing.com
> Sent: Thu, 7 April, 2011 17:02:04
> Subject: Re: [PyQt] why do closeEvent and destroyed slot not get
> called on accepting PyQt4 QDialog?
> I truly believe you are approaching this from the wrong angle. If you
> need to know when your QDialog is going away, you override closeEvent
> and do your cleanup from there.
> However, looking through the docs, it does not appear that destroy is
> actually a signal. It's called from the QWidget dtor, so it makes
> sense that if you call destroy(), you get the runtime error because
> you are deleting the C++ object before the Python object. Do not call
> destroy yourself - call self.close and override closeEvent. From
> there you can accept or reject closing the dialog, and do any cleanup
> prior to your dialog being destroyed.
> From the Qt Docs:
> void QWidget::destroy ( bool destroyWindow = true, bool
> destroySubWindows = true ) [protected]
> Frees up window system resources. Destroys the widget window if
> destroyWindow is true.
> destroy() calls itself recursively for all the child widgets, passing
> destroySubWindows for the destroyWindow parameter. To have more
> control over destruction of subwidgets, destroy subwidgets
> selectively first.
> This function is usually called from the QWidget destructor.
> On Thu, Apr 7, 2011 at 3:04 AM, Rui DaCosta <ruidc at yahoo.com> wrote:
> I know it can close it manually, the problem is that this is a
> simplification of a problem I had, in which we were expecting the
> QDialog to close as per the docs, but it did not.
> >The *real* problem we are facing, is a bit further down the line,
> > where we are getting the "RuntimeError: underlying C/C++ object has
> > been deleted" but we never receive a destroyed signal.
> >The only reason I need this signal or event is to do some teardown
> > code for some callbacks to avoid getting this c++ error elsewhere.
> ________________________________
> From: Demetrius Cassidy <dcassidy36 at gmail.com>
> >To: RuiDC <ruidc at yahoo.com>
> >Sent: Thu, 7 April, 2011 0:39:33
> >Subject: Re: [PyQt] why do closeEvent and destroyed slot not get
> > called on accepting PyQt4 QDialog?
> >
> >
> >If you want to close, just call self.close. It's a slot, so you can
> > map it to any signal. Also not sure why you want to know when your
> > widget is destroyed? Let Python take care of it, you should not
> > need to call sip.delete yourself. closeEvent is there if you need
> > to know _when_ your app was requested to close. If you want to
> > allow or reject closing the app, you need to use the QEvent object
> > which gets passed to that function.
> >
> >On Wed, Apr 6, 2011 at 5:27 PM, RuiDC <ruidc at yahoo.com> wrote:
> >>The question & code are here:
> >>http://stackoverflow.com/questions/5570402/why-do-closeevent-and-de
> >>stroyed-slot-not-get-called-on-accepting-pyqt4-qdialog
> >>
> >>
> >>but hopefully someone here can give me an answer on:
> >>1. how to get the closeEvent to fire from accepting (or do I have
> >> to do a self.close()?)
> >>2. how to get the destroyed message to print (or do I have to go
> >> through sip.delete(my_widget)?)
> >>3. why, if I comment out the del my_widget, and uncomment the
> >>my_widget.destroy() I get a:
> >>RuntimeError: underlying C/C++ object has been deleted
> >>on the destroy() without the print!  i.e. how is it that it can be
> >> destroyed but not raise the signal?
> >>
> >>Thanks in advance,
> >>R
> >>--
> >>View this message in context:
> >>http://old.nabble.com/why-do-closeEvent-and-destroyed-slot-not-get-
> >>called-on-accepting-PyQt4-QDialog--tp31336229p31336229.html
> >>
> >>Sent from the PyQt mailing list archive at Nabble.com.
> >>
> >>_______________________________________________
> >>PyQt mailing list    PyQt at riverbankcomputing.com
> >>http://www.riverbankcomputing.com/mailman/listinfo/pyqt

More information about the PyQt mailing list