Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to call a function right before a PyQt application ends?

I am collecting usage stats for my applications which include how much each session lasts. However, I can't seem to be able to save this information because None Of the signals I tried yet actually succeeds to call my report_session function.

This are the signals I have already tried:

  1. lastWindowClosed()
  2. aboutToQuit()
  3. destroyed()

Either these signals never get emitted or the application does not live long enough after that to run anything else. Here is my main:

app = QtGui.QApplication(sys.argv)

ui = MainWindow()
ui.app = app
QtCore.QObject.connect(ui, QtCore.SIGNAL("destroyed()"),  ui.report_session)
ui.show()
logger.info('Started!')
splash.finish(ui)

sys.exit(app.exec_())
like image 674
fccoelho Avatar asked Sep 30 '10 16:09

fccoelho


4 Answers

The method that Mark Byers posted will run after the main widget has been closed, meaning that its controls will no longer be available.

If you need to work with any values from controls on your form, you will want to capture the close event and do your work there:

class MainWidget(QtGui.QWidget):

    #...

    def closeEvent(self, event):
        print "closing PyQtTest"
        self.SaveSettings()
        # report_session()

Also, see the Message Box example in the ZetCode tutorial First programs in PyQt4 toolkit (near the end of the page). This shows how to accept or cancel the close request.

like image 195
Todd Avatar answered Sep 27 '22 18:09

Todd


Put the code between app.exec_ and sys.exit:

ret = app.exec_()
# Your code that must run when the application closes goes here
sys.exit(ret)
like image 45
Mark Byers Avatar answered Sep 27 '22 17:09

Mark Byers


To ensure that a Python function gets called at process termination, in general (with or without Qt involved;-), you can use the atexit module of the standard Python library:

import atexit

def whatever(): ...

atexit.register(whatever)

Out of prudence I would recommend against using a bound method instead of a function for this purpose -- it "should" work, but the destruction-phase of a process is always somewhat delicate, and the simpler you keep it, the better.

atexit won't trigger for a sufficiently-hard crash of a process, of course (e.g., if the process is killed with a kill -9, then by definition it's not given a chance to run any termination code) -- the OS sees to that;-). If you need to handle any crash no matter how hard you must do so from a separate "watchdog" process, a substantially subtler issue.

like image 33
Alex Martelli Avatar answered Sep 27 '22 18:09

Alex Martelli


Found this answer which involves overloading closeEvent().

it worked perfectly for me.

like image 28
fccoelho Avatar answered Sep 27 '22 17:09

fccoelho