IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GUI Python Discussion :

Ma class ne fonctionne pas dans un Thread [Python 3.X]


Sujet :

GUI Python

  1. #1
    Candidat au Club
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juillet 2011
    Messages : 4
    Points : 4
    Points
    4
    Par défaut Ma class ne fonctionne pas dans un Thread
    J'ai un script avec plusieurs fonctions, et une class (GUI) pour piloter ces fonctions.

    Je voudrai que cette class fonctionne dans un Thread et communique par une variable (avec acquire et release).
    Mais quand je lance >threading.Thread(target=MaClass)<, j'ai une erreur parce que la class n'est pas callable.

    Une solution ??

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Cela dépend de la manière dont ta classe est créée. A-t-elle une méthode __init__() ?

    Il faudra sans doute l'instancier avant et appeler une de ses méthodes pour faire tourner le thread.

    Tu parles de GUI à propos de cette classe, si elle doit gérer les rafraîchissements de widgets tu risques d'avoir des soucis, le serveur graphique n'apprécie pas que ses ressources soient utilisées par autre chose que le processus primaire du programme.

  3. #3
    Candidat au Club
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juillet 2011
    Messages : 4
    Points : 4
    Points
    4
    Par défaut
    Bonjour VinsS

    Oui j'ai essayé avec __init__
    def __init__(self):
    threading.Thread.__init__(self)
    def run():
    ...
    def stop():
    ...

    J'ai un programme pour gérer, assembler, dater, historiser plusieurs fichiers ou parties de fichiers.

    J'aimerai voire, intervenir sur son fonctionnement (qui peut être long) avec une interface graphique. Je suis en train de le modifier avec des 'acquire' et 'release' sur certaines variables. Dont une par exemple qui servira à passer des commandes (éxécuter avec eval).

    C'est pour cette raison que j'aimerai avoir cette interface graphique dans un Thread. Mais comme la class n'est pas callable, je ne voie pas comment faire. J'ai essayé avec une fonction qui appel cette class, ou l'importe etc, mais ça coince…

    Ma solution actuelle : une fonction principale. mais c'est très lourd (nommage, liaisons par exemple) et pas vraiment interactif.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par Bydouil Voir le message
    Je voudrai que cette class fonctionne dans un Thread et communique par une variable (avec acquire et release).
    Mais quand je lance >threading.Thread(target=MaClass)<, j'ai une erreur parce que la class n'est pas callable.

    Une solution ??
    Quel est le problème?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> class A: pass
    ...
    >>> callable(A)
    True
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Expert éminent

    Avatar de deusyss
    Homme Profil pro
    Expert Python
    Inscrit en
    Mars 2010
    Messages
    1 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Expert Python
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 659
    Points : 8 442
    Points
    8 442
    Par défaut
    Solution alternative sinon, le module multiprocessing, avec des pipes et/ou des queues.
    "La connaissance appartient à tout le monde" (Film Antitrust)

    Tout le nécessaire pour Python:
    *News/Accueil *Cours/tutoriels *FAQ
    *Forums *Outils dédiés *Mon espace personnel avec mes Articles, Cours et Tutoriels

  6. #6
    Expert éminent

    Avatar de deusyss
    Homme Profil pro
    Expert Python
    Inscrit en
    Mars 2010
    Messages
    1 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Expert Python
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 659
    Points : 8 442
    Points
    8 442
    Par défaut
    Si tu as obtenu reponse à ta question, n'oublie pas de passer le post à
    "La connaissance appartient à tout le monde" (Film Antitrust)

    Tout le nécessaire pour Python:
    *News/Accueil *Cours/tutoriels *FAQ
    *Forums *Outils dédiés *Mon espace personnel avec mes Articles, Cours et Tutoriels

  7. #7
    Candidat au Club
    Homme Profil pro
    Retraité
    Inscrit en
    Juillet 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juillet 2011
    Messages : 4
    Points : 4
    Points
    4
    Par défaut Une solution…
    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
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    #!/usr/bin/python3
    # -*- coding: Utf-8 -*-
     
     
    ##
    # Informations de cette version.
    ##
    __version__ = "140805.2107"
     
     
    ##
    # Module.
    ##
     
     
    from sys import exit, exc_info
    from os import linesep as LINESEP
    from time import sleep
    from tkinter import *
    import threading
     
     
    ##
    # Variables.
    ##
    # Retour de commande du démon.
    tampon_GUI = []
     
    # Référence le verrou.
    verrou = threading.Lock()
     
    # Temporisateur.
    pause = 0.1
     
    # Commande passée au démon.
    comm = []
     
     
    ##################################################
    # Interface graphique.
    ##################################################
    class GUI():
     
    	'''
            Interface graphique envoyant des chaînes de commande à un démon
            et affichant dans une Listbox() la réception des commandes.
            '''
     
     
    	# Déclaration du 'master'.
    	_ROOT = Tk()
     
    	# Une fenêtre de 600 x 600 avec un décalage de 50 à gauche et en haut.
    	_ROOT.geometry("%dx%d+%d+%d" % (600, 600, 50, 50))
     
     
    	# Initialisation.
    	def __init__(self):
     
    		# Temporisateur de '_ROOT'.
    		self.tmp_after = 500
     
    		# Initialise la Frame() de base.
    		self.frame = Frame(self._ROOT, background="blue", width=500, height=500).grid(padx=50, pady=50)
     
    		# Initialise la Listbox() à afficher.
    		self.list_box = Listbox(self.frame)
     
    		# Initialise l'ascenseur de la Listbox().
    		self.scroll = Scrollbar(self.list_box, command=self.list_box.yview, relief=RAISED)
     
    		# Lie l'ascenceur à la Listbox().
    		self.list_box.config(yscrollcommand=self.scroll.set)
     
    		# Positionne la Listbox().
    		self.list_box.place(x=55, y=55, width=400, height=400)
     
    		# Positionne l'ascenseur.
    		self.scroll.place(x=383, y=0, height=398)
     
    		# Le bouton 'Quitter'.
    #		Button(self.frame, text="Quitter", command=self.quitter).place(anchor=S)
     
    		# Active le temporisateur de '_ROOT'.
    		self.id = self._ROOT.after(self.tmp_after, self.lit_elem, self.list_box)
     
    		# Lance la boucle d'évènements.
    		self._ROOT.mainloop()
     
     
    	##
    	# Lecture d'un élément de la liste (en argument) à afficher.
    	##
    	def lit_elem(self, list_box):
     
    		'''
                    Transfert les str() du tampon dans la Listbox() fournie.
                    '''
     
    		print("GUI.lit_elem : fonctionnement du demon >", th_demon.is_alive(), "<.", sep="")
    		# Stop l'interface graphique si le démon est arrèté.
    		if not th_demon.is_alive():
    			self._ROOT.destroy()
     
    		# Accès en écriture au tampon de réception de l'exécution des commandes par le démon.
    		global tampon_GUI
     
    		# Dé-active le temporisateur de '_ROOT'.
    		# Sans cette fonction, l'instruction 'self._ROOT.after(…)' ne se répéterra pas.
    		self._ROOT.after_cancel(self.id)
     
    		# Bloc de transfert du tampon.
    		if tampon_GUI:
     
    			# Quitte le programme.
    			if tampon_GUI[0] == "exit()":
    				self._ROOT.destroy()
     
    			# Récupère la taille de la Listbox().
    			taille = list_box.size()
     
    			# Efface les éléments de la Listbox().
    			if taille:
    				print("GUI.lit_elem : efface les elements de la Listbox().", sep="")
    				list_box.delete(0, taille)
     
    			# Transfert les éléments à la Listbox().
    			for elem in tampon_GUI:
    				print("GUI.lit_elem : ajoute la ligne >", str(elem).encode("UTF-8"), "<.", sep="")
    				list_box.insert(END, str(elem))
     
    			# Attend le verrou pour effacer le tampon.
    			while not verrou.acquire():
     
    				# Temporisateur.
    				print("GUI.lit_elem : j'attend le verrou.", sep="")
    				sleep(pause)
     
    			# Efface le tampon.
    			print("GUI.lit_elem : vide le tampon.", sep="")
    			tampon_GUI = []
     
    			# Libère le verrou.
    			verrou.release()
    		print("GUI.lit_elem : fin de la fonction.", sep="")
     
    		# Ré-active le temporisateur de '_ROOT'.
    		self.id = self._ROOT.after(self.tmp_after, self.lit_elem, self.list_box)
     
     
    ##################################################
    # Communication entre l'interface GUI et le Thread.
    ##################################################
    def gui_thread():
     
    	'''
            Communication entre l'interface GUI et le Thread.
            '''
     
    	# Accès en écriture aux variables globales :
    	# comm : commande envoyer par l'interface graphique.
    	# tampon_GUI : tampon de transfert (de l'information) à l'interface graphique.
    	global comm, tampon_GUI
     
    	# Initialise le retour de commande.
    	retour = ""
     
    	# Si j'ai une commande.
    	print("gui_thread : len(comm) ", len(comm), ".", sep="")
    	if comm:
    		print("gui_thread : comm >", str(comm).encode("UTF-8"), "<.", sep="")
     
    		# Vérifie que le tampon soit vide.
    		if tampon_GUI:
    			print("gui_thread : le tampon n'est pas vide, donc return().", sep="")
    			print("gui_thread : tampon_GUI >", str(tampon_GUI), "<.", sep="")
     
    			# Retour au programme principal.
    			return
     
    		# Attend le verrou pour la lecture d'une commande.
    		while not verrou.acquire():
     
    			# Temporisateur.
    			print("gui_thread : j'attend le verrou.", sep="")
    			sleep(pause)
    		print("gui_thread : j'ai le verrou pour la lecture d'une commande.", sep="")
     
    		# Mémorise la commande.
    		print("gui_thread : memorise la commande >", str(comm[0]).encode("UTF-8"), "<.", sep="")
    		commande = comm.pop(0)
     
    		# Libère le verrou.
    		verrou.release()
     
    	# Pas de commande.
    	else:
    		print("gui_thread : je n'ai pas de commande, donc return().", sep="")
     
    		# Retour au programme principal.
    		return
     
    	# Bloc de test de la commande.
    	try:
     
    		print("gui_thread : test la commande >", str(commande).encode("UTF-8"), "<.", sep="")
    		retour = eval(commande)
     
    	# La commande est en erreur.
    	except:
     
    		# Passe l'erreur.
    		print("gui_thread : ERREUR de la commande >", str(commande).encode("UTF-8"), "<", LINESEP, str(exc_info()).encode("UTF-8"), sep="")
     
    		# Retour au programme principal.
    		return
     
    	# Attend le verrou pour le transfert des informations.
    	while not verrou.acquire():
     
    		# Temporisateur.
    		print("gui_thread : j'attend le verrou.", sep="")
    		sleep(pause)
     
    	# Pour un retour de commande au format tuple().
    	print("gui_thread : type(retour) ", type(retour), ".", sep="")
    	if isinstance(retour, tuple):
    		print("gui_thread : le retour de commande est au format tuple().", sep="")
    		tampon_GUI = retour
     
    	# Pour un retour de commande au format tuple().
    	elif isinstance(retour, list):
    		print("gui_thread : le retour de commande est au format list().", sep="")
    		tampon_GUI = tuple(retour)
     
    	# Pour un retour de commande dans un autre format.
    	else:
    		print("gui_thread : le retour de commande n'est pas au format tuple() ou list().", sep="")
    		tampon_GUI = tuple((retour,))
     
    	# Libère le verrou.
    	verrou.release()
     
     
    ##################################################
    # Démon.
    ##################################################
    def demon():
     
    	'''
            Script en tâche de fond.
            '''
     
    	global comm
     
    	# Fais quelque chose (1).
    	for i in range(10):
     
    		print("demon : fais quelque chose (1/", str(i), ").", sep="")
    		sleep(pause * 2)
     
    		# Vérifie le tampon de commandes de l'interface graphique.
    		gui_thread()
     
    		# Pour la démonstration.
    		if i == 5:
    			comm.append('listdir("/Applications/")')
     
    		# Pour la démonstration.
    		if i == 8:
    			comm.append('len(listdir("/Applications/Utilities/"))')
     
     
    	# Fais quelque chose (2).
    	for i in range(13):
     
    		print("demon : fais quelque chose (2/", str(i), ").", sep="")
    		sleep(pause * 2)
     
    		# Vérifie le tampon de commandes de l'interface graphique.
    		gui_thread()
     
    		# Pour la démonstration.
    		if i == 3:
    			comm.append('listdir("/Applications/Utilities/")')
     
    		# Pour la démonstration.
    		if i == 5:
    			comm.append('commande bidon, génère une erreur')
     
    		# Pour la démonstration.
    		if i == 8:
    			comm.append('("aa", "bb")')
     
    		# Pour la démonstration.
    		if i == 10:
    			comm.append('{"aa": "01"}')
     
    		# Pour la démonstration.
    		if i == 11:
    			comm.append('"exit()"')
     
    	th_demon._stop()
     
    ##
    # Initialise le démon.
    ##
    # Référence le démon.
    th_demon = threading.Thread(target=demon, name="demon", verbose=True)
    print("Test : initialisation du demon.", sep="")
     
    # Lance le démon.
    print("Test : lancement du demon.", sep="")
    th_demon.start()
     
    # Lancement de l'interface graphique.
    GUI()
     
    print("Test : fin du programme.", sep="")

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    J'ai parcouru en diagonale votre code.

    Le thread pousse des commandes dans une liste.
    Côté GUI, une tache répétitive dépile les commandes s'il y en a et met à jour l'affichage.

    Ca fonctionne et c'est très bien mais vous pourriez soumettre les mises à jour de l'affichage directement dans la boucle d’événement. C'est déjà une liste et pas besoin de la gérer.

    Votre code est un peu trop touffu pour que je m'amuse à le modifier.
    Par contre vous pourriez regarder l'exemple que j'ai posté hier sur le même sujet.

    Bon courage
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 02/12/2009, 08h27
  2. Réponses: 14
    Dernier message: 22/02/2008, 19h01
  3. [MySQL] Condition ne fonctionnant pas dans une classe
    Par lodan dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 09/02/2007, 16h38
  4. Réponses: 1
    Dernier message: 27/10/2005, 21h48
  5. Réponses: 4
    Dernier message: 15/01/2004, 22h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo