Récits d'un GeekTrotter Carnet de bord binaire

10mai/111

Recette Python Qt4: QSingleApplication (PySide)

Grâce à Renato Filho qui m'a aidé sur les forums Qt, j'ai écris une classe QSingleApplication pour PySide qui permet de ne lancer votre programme qu'une seule fois.

En plus et surtout, cette classe permet de passer les arguments des nouvelles exécutions du programme à la première (et seule restante) exécution.

La vidéo suivante résume les fonctionnalités :

L'idée est d'utiliser QLocalServer / QLocalSocket pour effectuer les vérifications et communiquer entre les exécutions du programme.

Primo, on crée un socket et on essaie de se connecter au serveur enregistré avec le nom du programme.

        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(self.applicationName(), QIODevice.WriteOnly)

Si la connexion réussie, ça veut dire qu'il y avait déjà un serveur qui tournait, donc que le programme est déjà lancé.
On va donc essayer de se connecter à ce programme.
Si le nouvel appel du programme a été fait sans paramètres, on affiche une alerte comme quoi le programme est déjà lancé et on quitte.
Si par contre on a des paramètres au nouvel appel, on les envoit au programme qui tourne déjà.

    def connectToExistingApp(self):
        if len(sys.argv)>1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            QMessageBox.warning(None, self.tr("Already running"), self.tr("The program is already running."))
            # Quit application in 250 ms
            QTimer.singleShot(250, self.quit)

Si la connexion échoue, cela signifie que c'est la première fois qu'on lance le programme, donc on le lance ainsi qu'un serveur qui écoute les éventuels futurs lancements de ce même programme.

    def startApplication(self):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.applicationName()):
            self.m_server.newConnection.connect(self.getNewConnection)
            self.mainWindow.show()
        else:
            QMessageBox.critical(None, self.tr("Error"), self.tr("Error listening the socket."))

Vous pouvez télécharger le code complet sur Gitorious: qSingleApplication.py