79 votes

Quelle est la bonne façon de faire que mon application PyQt se ferme lorsqu'elle est supprimée de la console (Ctrl-C)?

Quelle est la bonne façon de faire que mon application PyQt se ferme lorsqu'elle est supprimée de la console (Ctrl-C)?

Actuellement (je n'ai rien fait de spécial pour gérer les signaux Unix), mon application PyQt ignore SIGINT (Ctrl + C). Je veux qu'il se comporte bien et qu'il arrête quand il est tué. Comment devrais-je faire ça?

52voto

Artur Gaspar Points 1664

17.4. signal - Définir des gestionnaires d'événements pour les événements asynchrones

Bien que Python les gestionnaires de signaux sont appelés de manière asynchrone autant que le Python utilisateur est concerné, ils ne peuvent se produire entre les "atomique" instructions de l'interpréteur Python. Cela signifie que les signaux arrivant pendant de longs calculs mis en œuvre uniquement en C (comme l'expression régulière correspond sur de grands corps de texte) peut être retardé pour une quantité arbitraire de fois.

Cela signifie que Python ne peut pas traiter les signaux de la boucle d'événement de Qt est en cours d'exécution. Seulement lorsque l'interpréteur Python run (quand le QApplication se ferme, ou lorsqu'une fonction Python est appelée à partir de l'intervalle Qt) le gestionnaire de signal sera appelée.

Une solution est d'utiliser un QTimer de laisser l'interprète de courir de temps à temps.

Notez que, dans le code ci-dessous, si il n'y a pas de fenêtres ouvertes, l'application va se fermer après la boîte de message quel que soit le choix de l'utilisateur en raison de QApplication.quitOnLastWindowClosed() == True. Ce comportement peut être modifié.

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_())

Une autre solution possible, comme indiqué par LinearOrbit, est - signal.signal(signal.SIGINT, signal.SIG_DFL), mais il n'autorise pas les gestionnaires personnalisés.

45voto

LinearOrbit Points 211

Si vous souhaitez simplement avoir ctrl-c fermer l'application - sans être « gentil » / gracieuse à ce sujet - puis de http: //www.mail- archive.com/pyqt@riverbankcomputing.com/msg13758.html , vous pouvez utiliser ce:

 import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

import sys
from PyQt4.QtCore import QCoreApplication
app = QCoreApplication(sys.argv)
app.exec_()
 

Apparemment, cela fonctionne sous Linux, Windows et OSX - je l’ai seulement testé jusqu’à présent (et ça marche).

7voto

parcouss Points 126

J'ai trouvé un moyen de faire ça. L'idée est de forcer qt à traiter les événements assez souvent et, dans un appel python, à capturer le signal SIGINT.

 import signal, sys
from PyQt4.QtGui import QApplication, QWidget # also works with PySide

# You HAVE TO reimplement QApplication.event, otherwise it does not work.
# I believe that you need some python callable to catch the signal
# or KeyboardInterrupt exception.
class Application(QApplication):
    def event(self, e):
        return QApplication.event(self, e)

app = Application(sys.argv)

# Connect your cleanup function to signal.SIGINT
signal.signal(signal.SIGINT, lambda *a: app.quit())
# And start a timer to call Application.event repeatedly.
# You can change the timer parameter as you like.
app.startTimer(200)

w = QWidget()
w.show()
app.exec_()
 

1voto

karolx Points 271

Vous pouvez utiliser le mécanisme standard de gestion des signaux unix python:

 import signal 
import sys
def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print 'Press Ctrl+C'
while 1:
        continue
 

Où, en signal_handler vous pouvez libérer toutes les ressources (fermer toutes les sessions de la base de données, etc.) et fermer doucement votre application.

Exemple de code tiré d' ici

1voto

xioxox Points 667

Je pense avoir une solution plus simple:

 import signal
import PyQt4.QtGui

def handleIntSignal(signum, frame):
    '''Ask app to close if Ctrl+C is pressed.'''
    PyQt4.QtGui.qApp.closeAllWindows()

signal.signal(signal.SIGINT, handleIntSignal)
 

Cela indique simplement à l'application d'essayer de fermer toutes les fenêtres si vous appuyez sur ctrl + c. S'il existe un document non enregistré, votre application doit afficher une boîte de dialogue de sauvegarde ou d'annulation comme si elle avait été fermée.

Vous aurez peut-être également besoin de connecter le signal QApplication lastWindowClosed () à la fente quit () pour que l'application se ferme réellement lorsque les fenêtres sont fermées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X