Partage
  • Partager sur Facebook
  • Partager sur Twitter

Création interface graphique avec PyQt

Une fonction bloque le reste du code

Sujet résolu
    9 juillet 2013 à 19:15:23

    Salut à tous,

    Plutôt débutant en Python et surtout en PyQt, je butte sur un problème que peut-être l'un d'entre vous saura résoudre : je souhaite créer une interface graphique avec PyQt, qui m'aidera par la suite pour un projet électronique.
    J'utilise 11 pushButton dont 9 sans label: les 9 sans label pour afficher une couleur, en matrice 3X3 (il y a d'ailleurs peut-être mieux que des pushButton...). Les 2 autres servent à lancer (Run) et stopper (Stop) du code.

    Seulement, une fois appuyé le bouton 'Run', celui-ci reste cliqué et mon code s'exécute (sauf la partie SetStyleSheet, mon pushButton ne change pas de color-background), le bouton 'Stop' restant grisé.

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    # modules a importer
    from PyQt4.QtGui import *
    from PyQt4.QtCore import * # inclut QTimer..
    import os,sys,time
    
    from pushButton04 import * # fichier obtenu à partir QtDesigner et pyuic4
    
    class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
    	def __init__(self, parent=None):
    		QWidget.__init__(self) # initialise le Qwidget principal
    		self.setupUi(parent) # Obligatoire
    
    		#Ici, personnalisez vos widgets si nécessaire
    
    		#Réalisez les connexions supplémentaires entre signaux et slots
    		self.connect(self.pushButton_11, SIGNAL("clicked()"), self.pushButtonRunClicked)
    		self.connect(self.pushButton_10, SIGNAL("clicked()"), self.pushButtonStopClicked)
    		# connecte le signal Clicked de l'objet bouton radio à l'appel de la fonction voulue
    
    		# variables utiles
    		self.active = 0
    
    	# les fonctions appelées, utilisées par les signaux
    	def pushButtonRunClicked(self):
    		print("Bouton 'Run' cliqué")
    		self.pushButton_10.setEnabled(True)
    		self.pushButton_11.setEnabled(False)
    		self.active = 1
    		
            r = 0
    		g = 0
    		b = 0
    		
    		while self.active == 0 :
    			r = r+1
    			self.pushButton.setStyleSheet(QString.fromUtf8("background-color: rgb("+str(r)+","+str(g)+","+str(b)+");"))
    			print("R = "+str(r)+", G = "+str(g)+", B = "+str(b))
    			time.sleep(1)
    		
    		print("self.active = "+str(self.active))
    		
    	def pushButtonStopClicked(self):
    		print("Bouton 'Stop' cliqué")
    		self.pushButton_10.setEnabled(False)
    		self.pushButton_11.setEnabled(True)
    		self.active = 0		
    
    def main(args):
    	a=QApplication(args) # crée l'objet application
    	f=QWidget() # crée le QWidget racine
    	c=myApp(f) # appelle la classe contenant le code de l'application
    	f.show() # affiche la fenêtre QWidget
    	r=a.exec_() # lance l'exécution de l'application
    	return r
    
    if __name__=="__main__": # pour rendre le code exécutable
    	main(sys.argv) # appelle la fonction main
    

    J'ai bien le print qui s'affiche en console, avec r qui s'incrémente une fois par seconde. Mais mon premier pushButton de la matrice reste désespérément noir..

    Je suis ouvert à toute suggestion pour avance sur ce problème, merci d'avance !

    -
    Edité par schizophrene 9 juillet 2013 à 19:18:00

    • Partager sur Facebook
    • Partager sur Twitter
      9 juillet 2013 à 21:43:44

      C'est tout à fait normal : Qt utilise une boucle d'événement qui est appelée dans temps à autre et qui sert à traiter les événements de l'interface (entre autre), comme le redimensionnement, le changement de couleurs, etc.

      Qt ne peut pas exécuter cette boucle d'événements qu'une fois l'appel à ton slot terminé. C'est à dire qu'il ne mettra à jour ton label qu'à la fin de ta boucle lorsque les événements comme les updates seront traités.
      Tu peux néanmoins forcer le traitement des événements en appelant QCoreApplication.processEvent() à chaque tour de boucle.

      Mais tu as un deuxième problème : ton appel à la fonction sleep qui bloque ton processus et du coup freeze ton interface. Tu devrais regarder du côté de QTimer.

      • Partager sur Facebook
      • Partager sur Twitter
        10 juillet 2013 à 10:48:39

        Salut erd, et merci pour ton intervention.

        Effectivement, le QCoreApplication.processEvents() fonctionne bien, à condition d'utiliser un QTimer. Ceci dit, je dois mal utiliser ce dernier, car en changeant la valeur du setInterval(), je n'ai aucune modification de la durée entre 2 mise à jour du GUI.

        def pushButtonRunClicked(self):
        		print("Bouton 'Run' cliqué")
        		self.pushButton_10.setEnabled(True)
        		self.pushButton_11.setEnabled(False)
        		self.active = 1
        		
        		self.timer = QtCore.QTimer()
        		self.timer.setInterval(1000000)
        		
        		r = 0
        		g = 0
        		b = 0
        		
        		while self.active == 1 :
        			r = r+1
        			self.pushButton.setStyleSheet(QString.fromUtf8("background-color: rgb("+str(r)+","+str(g)+","+str(b)+");"))
        			QCoreApplication.processEvents()
        			print("R = "+str(r)+", G = "+str(g)+", B = "+str(b))
        			#time.sleep(1)
        			self.timer.start()



        • Partager sur Facebook
        • Partager sur Twitter
          10 juillet 2013 à 10:59:40

          QTimer ne sert pas à faire des pauses mais à appeler un slot ou un signal à intervalle régulier, un peu comme le tic d'une horloge.

          En fait, dans ton slot, il faut uniquement que tu lances ton timer. Tu connectes le signal QTimer.timeout() à un autre slot dans lequel tu effectues ton traitement.

          • Partager sur Facebook
          • Partager sur Twitter
            10 juillet 2013 à 14:12:41

            Oui, c'est ce que j'ai vu tout de suite après mon précédent message, en me renseignant plus sur QTimer.

            Maintenant, je me bats avec des global name non déclarés --'

            • Partager sur Facebook
            • Partager sur Twitter
              10 juillet 2013 à 21:48:19

              Problèmes réglés, et utilisation entièrement comprise :)

              Je remets mon code 'Main' en entier, ça pourra toujours aider quelqu'un:

              #!/usr/bin/python
              # -*- coding: utf-8 -*-
              
              # modules a importer
              from PyQt4.QtGui import *
              from PyQt4.QtCore import * # inclut QTimer..
              import os,sys
              
              from pushButton04 import * # fichier obtenu à partir QtDesigner et pyuic4
              
              class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
              	def __init__(self, parent=None):
              		QWidget.__init__(self) # initialise le Qwidget principal
              		self.setupUi(parent) # Obligatoire
              				
              		#Ici, personnalisez vos widgets si nécessaire
              		
              		# variables utiles
              		self.r = 0
              		self.timer = QtCore.QTimer()
              
              		#Réalisez les connexions supplémentaires entre signaux et slots
              		self.connect(self.pushButton_11, SIGNAL("clicked()"), self.pushButtonRunClicked)
              		self.connect(self.pushButton_10, SIGNAL("clicked()"), self.pushButtonStopClicked)
              		self.connect(self.timer, SIGNAL("timeout()"), self.updateGUI)
              		
              		# les fonctions appelées, utilisées par les signaux
              	
              	# démarrage du timer qui servira à raffraichir l'affichage du GUI
              	def updateTimer(self):
              		self.timer.setInterval(100)
              		self.timer.start()
              	
              	# le bouton 'Run' devient grisé, bouton 'Stop' est activé. Appel de la fonction démarrant le timer	
              	def pushButtonRunClicked(self):
              		print("Bouton 'Run' cliqué")
              		self.pushButton_10.setEnabled(True)
              		self.pushButton_11.setEnabled(False)
              		self.updateTimer()
              	
              	# le bouton 'Run' est activé, bouton 'Stop' devient grisé. Le timer est arrêté
              	def pushButtonStopClicked(self):
              		print("Bouton 'Stop' cliqué")
              		self.pushButton_10.setEnabled(False)
              		self.pushButton_11.setEnabled(True)
              		self.timer.stop()
              	
              	# changement des valeurs pour le background et actualisation	
              	def updateGUI(self):
              		self.r += 1
              		self.pushButton.setStyleSheet(QString.fromUtf8("background-color: rgb("+str(self.r)+",0,0;)"))
              		QCoreApplication.processEvents()
              		print("R = "+str(self.r))#+", G = "+str(g)+", B = "+str(b))
              
              def main(args):
              	a=QApplication(args) # crée l'objet application
              	f=QWidget() # crée le QWidget racine
              	c=myApp(f) # appelle la classe contenant le code de l'application
              	f.show() # affiche la fenêtre QWidget
              	r=a.exec_() # lance l'exécution de l'application
              	return r
              
              if __name__=="__main__": # pour rendre le code exécutable
              	main(sys.argv) # appelle la fonction main
              



              • Partager sur Facebook
              • Partager sur Twitter

              Création interface graphique avec PyQt

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown