Quelle est la manière correcte de faire mon PyQt de fermeture de l'application lorsqu'ils sont tués à partir de la console (Ctrl-C)?
Quelle est la manière correcte de faire mon PyQt de fermeture de l'application lorsqu'ils sont tués à partir de la console (Ctrl-C)?
Actuellement (je n'ai rien fait de spécial pour gérer les signaux unix), mon PyQt application ignore SIGINT (Ctrl+C). Je veux qu'il se comporte correctement et cesser de fumer lorsqu'il est tué. Comment dois-je faire?
- Je n'ai jamais compris pourquoi, dans presque tous script python dans le monde s'arrête avec un ctrl+c, excepté pour pyqt apps. Pas de doute, il ya une bonne raison pour cela, mais à la fin c'est très ennuyeux.
- nous allons résoudre une fois pour toutes 🙂
- elle apparaît à un problème de conception: mail-archive.com/[email protected]/msg13757.html. Toute solution impliquant des exceptions ou similaire se sent juste hacky 🙁
- vous pouvez utiliser Ctrl + \ tuer l'application à partir du terminal.
Vous devez vous connecter pour publier un commentaire.
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.
Noter 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é.
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.Si vous souhaitez tout simplement avoir ctrl-c fermer l'application sans être "nice"/gracieux - ensuite de http://www.mail-archive.com/[email protected]/msg13758.html, vous pouvez utiliser ceci:
Apparemment cela fonctionne sur Linux, Windows et OSX - j'ai uniquement testé sur Linux pour l'instant (et ça marche).
La boucle d'événement de Qt est implémenté en C(++). Cela signifie, que, s'il s'exécute et pas de code Python est appelée (par exemple. par un Qt signal connecté à un Python logement), les signaux sont notés, mais le Python les gestionnaires de signaux ne sont pas appelés.
Mais, depuis la version 2.6 de Python et Python 3, vous pouvez provoquer Qt pour exécuter une fonction Python lorsqu'un signal avec un gestionnaire est reçu à l'aide d'
signal.set_wakeup_fd()
.C'est possible, parce que, contrairement à la documentation, le faible niveau du gestionnaire de signal n'est pas seulement de définir un indicateur pour la machine virtuelle, mais il peut aussi écrire un octet dans le fichier descripteur de par
set_wakeup_fd()
. Python 2 écrit un octet NUL, Python 3 écrit le numéro du signal.Par la sous-classement d'une classe Qt qui prend un descripteur de fichier et fournit un
readReady()
signal, comme par exempleQAbstractSocket
, la boucle d'événements pour exécuter une fonction Python à chaque fois qu'un signal (avec un gestionnaire) est reçu origine du gestionnaire de signal pour exécuter presque instantanément sans avoir besoin de minuteries:socket.socketpair
. (J'ai essayébackports.socketpair
, mais cela ne fonctionne pas non plus).ValueError: the fd 10 must be in non-blocking mode
lors de l'essai avec Python 3.5.3 sur macOS.self.wsock.setblocking(False)
résout le problème mentionné dans mon précédent féliciter.J'ai trouvé une façon de le faire. L'idée est de forcer qt pour traiter les événements assez souvent et dans un python callabe pour attraper le signal SIGINT.
signal.signal(signal.SIGINT, lambda *a: app.exit(-2))
Vous pouvez utiliser le standard de python unix signaux d'un mécanisme de gestion:
où dans
signal_handler
vous pouvez libérer toutes les ressources (fermer toutes les db sessions etc) et fermer doucement votre application.Exemple de Code pris de ici
Je pense avoir une solution plus simple:
Cela dit, l'application tente de fermer toutes les fenêtres ctrl+c est pressé. Si il y a un document non enregistré, votre application doit afficher une enregistrer ou d'annuler de la boîte de dialogue, comme si c'était sorti.
Vous pouvez aussi avoir besoin de connecter le QApplication signal lastWindowClosed() sur le slot quit() afin d'obtenir l'application de fait de sortie lorsque les fenêtres sont fermées.
La réponse de Artur Gaspar travaillé pour moi quand la fenêtre de terminal a été mis en avant, mais ne serait pas fonctionner lorsque le GUI était. Afin d'obtenir mon GUI pour fermer (qui hérite de QWidget) je devais définir la fonction suivante dans la classe:
Vérification pour vous assurer que l'événement clé est de 67 permet de s'assurer que " c " était pressé. Puis vérification de l'événement modificateurs détermine si la touche ctrl enfoncée lors de la " c " a été publié.