Bonjour,
Je cherchais une méthode pour empêcher un programme PyQt4 d'être lancé une seconde fois alors qu'il y avait déjà une instance en activité.
J'ai cherché un code PyQt4 sur le web et je n'en ai pas trouvé. J'ai aussi trouvé des 'usines à gaz' en C++, difficiles à traduire en Python.
Finalement, le plus simple a été de traduire en PyQt4 le code en C de la FAQ Qt: http://qt.developpez.com/faq/?page=q...ples-instances.
Cela a donné le code suivant:
Le principe est très simple:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 #! /usr/bin/python # -*- coding: utf-8 -*- # Python v2.7 import sys from PyQt4 import QtCore, QtGui ############################################################################# class Fenetre(QtGui.QMainWindow): #======================================================================== def __init__(self, parent=None): super(Fenetre,self).__init__(parent) ############################################################################# if __name__ == "__main__": # lancement du graphique app = QtGui.QApplication(sys.argv) # on prépare la création d'une zone partagée avec une clé quelconque # mais cette clé ne doit pas être utilisée par un autre programme! sharedMemory = QtCore.QSharedMemory(QtCore.QString(u"D6BB05B2919732D8F29045842531CAD23162E1B9")) # on essaye de créer cette zone partagée de taille 50 (quelconque): # si ce n'est pas possible, c'est qu'elle existe déjà, et donc # qu'elle a été créée par une instance précédente du même programme! if not sharedMemory.create(50): QtGui.QMessageBox.warning(None, u"Vérification", u""" Attention: ce programme est déjà en cours d'exécution utilisez la version déjà lancée! """) sys.exit() # lancement de la fenêtre fen = Fenetre() fen.show() sys.exit(app.exec_())
1- on créé une clé (une chaine) unique pour le programme concerné
2- on cherche à créer une zone de mémoire partagée avec cette clé
3- si ça ne marche pas, c'est que la zone existe déjà avec la même clé, et donc qu'elle a déjà été créée par une instance précédente du programme.
Pour créer une clé, il suffit que la chaine soit unique. Vous pouvez prendre un GUID comme proposé par la FAQ Qt, mais n'importe quelle chaine peut faire l'affaire. J'ai même essayé avec succès: "nimportequoipourvuquecamousse" . Plus sérieusement, si vous manquez d'inspiration, vous pouvez fabriquer une chaine de 40 caractères au hasard avec:
Et ça a l'air de marcher: le 1er lancement du programme se fait, mais le second lancement est empêché (avec message). Ceci à condition de lancer le programme normalement (en console ou un lanceur graphique), et pas à partir d'un outil de développement.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 from random import randint guidrand = lambda n=40, alphanum=u"0123456789ABCDEF": ''.join([alphanum[randint(0,len(alphanum)-1)] for i in xrange(n)]) print guidrand() D6BB05B2919732D8F29045842531CAD23162E1B9
Ça fonctionne de la même façon sous Windows et sous Linux (sous Mac OS_X, je ne sais pas).
Avec cx_freeze sous Windows, ça marche aussi, même si dans certains cas, il faut attendre une minute pour que Windows fasse disparaitre la précédente zone mémoire partagée.
Sous Windows, j'ai même essayé de "tuer" sauvagement la 1ère instance avec le gestionnaire des tâches, pour vérifier que la zone partagée était supprimée aussi: et oui!
Mais alors, quel est mon problème? Il est ici: la méthode me parait tellement simple que j'ai un doute. Aussi, j'aimerais que plusieurs parmi vous essayent pour vérifier que ça marche dans tous les cas!. Il suffit de récupérer le code en copier-coller, et d'avoir déjà Python 2.x et PyQt4.
Si ça marche, en plus de l'utiliser sur mes programmes, je le proposerai à la FAQ PyQt4.
Merci d'avance.
Tyrtamos
[EDIT]: petite modif du code: en cas de détection d'échec, après la fenêtre du message d'erreur, il faut remplacer le simple sys.exit() par:
Dans ce cas, ça fonctionne très bien et sans attente avec cx_freeze!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 app.quit() sys.exit(0)
Partager