Jay
Jay

Reputation: 3479

Execute code when QWidget is actually destroyed, not just closed

I have created a custom QDialog class and overridden the closeEvent to just hide the dialog as it is a child of another widget. My dialog must only close when its parent is closed and not when it's accepted, rejected or the user clicks the close button.

This all works fine but now I need to open a connection to a database and only close it when the dialog is destroyed not just when it's closed.

My code:

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

def Log_Closed():
    print "Bye bye"

class My_dlg(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__( self, parent )

        #self.conn = open_connection()
        print "Connection Opened"

        close_btn  = QPushButton("Actually Close")
        QVBoxLayout(self).addWidget(close_btn)

        close_btn.clicked.connect(self.Actually_Close)
        self.destroyed.connect(Log_Closed)

    def Actually_Close(self):
        print "Actually Close"
        self.parent().close()

    def closeEvent(self, event):
        if event.type() == QEvent.Close:
            event.ignore()
            self.hide()
            print "hidden"

    # And I guess I need something like
    def destroyEvent(self, event):
        #self.conn.close()
        print "Connection Closed"
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main= QMainWindow()
    tsd = My_dlg(main)
    tsd.show()
    sys.exit(app.exec_())

Any ideas?

Upvotes: 1

Views: 5729

Answers (1)

jmk
jmk

Reputation: 1988

To receive notification when a QObject is deleted, connect to its destroyed(QObject*) signal.

However, in Python, object deletion is less predictable than it is in C++ because objects are garbage collected. For example, see all of the caveats associated with __del__() in the Python documentation. They may not be deleted when the program exits, which is probably why you're not receiving the signal.

Instead of relying on deletion of the dialog, you could manage the database connection explicitly. In this simple example, you could even use a context manager for slightly nicer code.


Either way, here's a version of your code that behaves as you expect: https://gist.github.com/3827718

The changes I made were:

  • Set app.setQuitOnLastWindowClosed to make sure that the application doesn't quit when the dialog closes. I presume this is the behavior you want, because otherwise this question doesn't make sense.

  • Set Qt.WA_DeleteOnClose to False on the dialog to prevent it from deleting itself when closed. This is preferable to overriding closeEvent.

  • In Actually_Close(), the dialog deletes itself (which will also close it). This triggers the destroyed signal.

With this code, the output is as you expect when you click the button:

Connection Opened
Actually Close
Bye bye

Upvotes: 8

Related Questions