Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to make my PyQt application quit when killed from the console (Ctrl-C)?

What is the correct way to make my PyQt application quit when killed from the console (Ctrl-C)?

Currently (I have done nothing special to handle unix signals), my PyQt application ignores SIGINT (Ctrl+C). I want it to behave nicely and quit when it is killed. How should I do that?

like image 377
static_rtti Avatar asked Feb 08 '11 21:02

static_rtti


2 Answers

17.4. signal — Set handlers for asynchronous events

Although Python signal handlers are called asynchronously as far as the Python user is concerned, they can only occur between the “atomic” instructions of the Python interpreter. This means that signals arriving during long calculations implemented purely in C (such as regular expression matches on large bodies of text) may be delayed for an arbitrary amount of time.

That means Python cannot handle signals while the Qt event loop is running. Only when the Python interpreter run (when the QApplication quits, or when a Python function is called from Qt) the signal handler will be called.

A solution is to use a QTimer to let the interpreter run from time to time.

Note that, in the code below, if there are no open windows, the application will quit after the message box regardless of the user's choice because QApplication.quitOnLastWindowClosed() == True. This behaviour can be changed.

import signal import sys  from PyQt4.QtCore import QTimer from PyQt4.QtGui import QApplication, QMessageBox  # Your code here  def sigint_handler(*args):     """Handler for the SIGINT signal."""     sys.stderr.write('\r')     if QMessageBox.question(None, '', "Are you sure you want to quit?",                             QMessageBox.Yes | QMessageBox.No,                             QMessageBox.No) == QMessageBox.Yes:         QApplication.quit()  if __name__ == "__main__":     signal.signal(signal.SIGINT, sigint_handler)     app = QApplication(sys.argv)     timer = QTimer()     timer.start(500)  # You may change this if you wish.     timer.timeout.connect(lambda: None)  # Let the interpreter run each 500 ms.     # Your code here.     sys.exit(app.exec_()) 

Another possible solution, as pointed by LinearOrbit, is signal.signal(signal.SIGINT, signal.SIG_DFL), but it doesn't allow custom handlers.

like image 121
Artur Gaspar Avatar answered Oct 19 '22 14:10

Artur Gaspar


If you simply wish to have ctrl-c close the application - without being "nice"/graceful about it - then from http://www.mail-archive.com/[email protected]/msg13758.html, you can use this:

import signal signal.signal(signal.SIGINT, signal.SIG_DFL)  import sys from PyQt4.QtCore import QCoreApplication app = QCoreApplication(sys.argv) app.exec_() 

Apparently this works on Linux, Windows and OSX - I have only tested this on Linux so far (and it works).

like image 42
LinearOrbit Avatar answered Oct 19 '22 13:10

LinearOrbit