Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Qt+Python]Lancer l'affichage dans boucle while

Sujet résolu
    13 décembre 2011 à 9:58:50

    Bonjour à tous. J'ai un petit problème, je n'arrive pas à afficher des valeurs calculées dans une boucle while. En fait je ne sors pas de cette boucle et n'arrive donc pas à appeler PyQt. On m'a dit que je pouvais utiliser "qApp.processEvents()" mais cela ne donne rien chez moi, je dois mal l'utiliser.

    Voici le code simplifié:
    from visa import *
    from pylab import *
    import sys
    from PyQt4 import QtGui
    import numpy as np
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
    
    
    #===============================================================================
    # 
    #===============================================================================
    
    class CPUMonitor(FigureCanvas):
        def __init__(self,parent):
    
           
            self.fig = Figure()
            self.ax = self.fig.add_subplot(111)   
            FigureCanvas.__init__(self, self.fig)       
    
            # generates first "empty" plots
            self.user, self.nice = [], []
            self.l_user, = self.ax.plot([], self.user, label='Voltage')
            self.l_nice, = self.ax.plot([], self.nice, label='Voltage2')
            
            # force a redraw of the Figure
            self.fig.canvas.draw()
    
    
            self.principal()
    
            def principal(self) :          
            stop = 0
            while stop==0 : 
                time.sleep(1)
                result1 = 0.2
    
                time.sleep(1)
                result2 = 0.3       
        
        #          append new data to the datasets
                self.user.append(result1)
                self.nice.append(result2)
            
                self.l_user.set_data(range(len(self.user)), self.user)
                self.l_nice.set_data(range(len(self.nice)), self.nice)
        	
                # force a redraw of the Figure
                self.fig.canvas.draw()
                FigureCanvas.updateGeometry(self)  
                
                qApp.processEvents()
    
    
    class ApplicationWindow(QtGui.QMainWindow):
        """Example main window"""
        def __init__(self):
            # initialization of Qt MainWindow widget
            QtGui.QMainWindow.__init__(self)
            # set window title
            self.setWindowTitle("QHE manip")
            # instantiate a widget, it will be the main one
            self.main_widget = QtGui.QWidget(self)
            # create a vertical box layout widget
            vbl = QtGui.QVBoxLayout(self.main_widget)
            # instantiate our Matplotlib canvas widget
            qmc = CPUMonitor(self.main_widget)
            # instantiate the navigation toolbar
            ntb = NavigationToolbar(qmc, self.main_widget)
            # pack these widget into the vertical box
            vbl.addWidget(qmc)
            vbl.addWidget(ntb)
    
            # set the focus on the main widget
            self.main_widget.setFocus()
            # set the central widget of MainWindow to main_widget
            self.setCentralWidget(self.main_widget)
    
    # create the GUI application
    
    qApp = QtGui.QApplication(sys.argv)
    # instantiate the ApplicationWindow widget
    aw = ApplicationWindow()
    # show the widget
    aw.show()
    # start the Qt main loop execution, exiting from this script
    # with the same return code of Qt application
    sys.exit(qApp.exec_())
    







    <code type="python"></code>

    Quelqu'un a une idée?

    Merci d'avance!

    Fabien
    • Partager sur Facebook
    • Partager sur Twitter
      16 décembre 2011 à 1:49:31

      Bonjour,

      Tu ne peux pas utiliser de boucles infinis, ça bloque le programme. Rien ne sert d'envoyer des évènements si ils ne sont jamais exécutes.
      Tu peux soit utiliser un thread soit un QTimer (qui me paraît plus approprié dans ton cas).
      • Partager sur Facebook
      • Partager sur Twitter
        16 décembre 2011 à 12:13:54

        Salut,

        Je ne comprend pas pourquoi je ne peux pas utiliser de boucles infinies. Je t'explique le but de mon programme. J'essaye de faire un programme qui permette de piloter une manip de physique. C'est à dire demander à des appareils de mettre une tension et à d'autres de mesurer un courant ou une tension, les mettre dans un fichier et les afficher sur un graph. Certaines manips durent plusieurs jours d'où je pense l'utilité d'avoir une boucle infinie je pense. Je voulais faire un bouton changeant la valeur de "stop" et donc pouvoir arrêter cette boucle.

        En réalité ce que j'aimerais faire c'est appeler l'interface graphique à chaque fois que je mesure un nouveau point (ici c'est constant result1 = 0.2) afin de pouvoir le voir sur mon écran. J'ai éssayer d'utiliser un timer. Celà marche parfaitement si je n'ai pas de sleep, or les sleep(indispensables pour que la tension soit bien stable dans l'échantillon que j'étudie dans ma manip) rendent l'éxecution non immédiate et donc ça lague vraiment pas mal le timer se déclenche toute les secondes et principal met deux secondes à s'éxecuter.

        Dans tous les cas merci beaucoup pour ton aide,

        Fabien
        • Partager sur Facebook
        • Partager sur Twitter
          17 décembre 2011 à 0:56:14

          Citation : pseudoprovoc

          Je ne comprend pas pourquoi je ne peux pas utiliser de boucles infinies



          En fait les évènements Qt sont eux aussi traitées dans une boucle infinie. Ce que tu fais revient un peu à ça:

          while True:
              "ton programme"
          
          while True:
              "Les évènements Qt qui sont jamais traités"
          


          Les sleep bloquent également le programme. Tu dois pouvoir t'en sortir avec des timer. Si tu as 2 sleep, il faut utiliser 2 timers.
          peut-être quelque chose dans ce genre là (je n'ai pas testé)

          class CPUMonitor(FigureCanvas):
              def __init__(self,parent):
          
                 
                  self.fig = Figure()
                  self.ax = self.fig.add_subplot(111)   
                  FigureCanvas.__init__(self, self.fig)       
          
                  # generates first "empty" plots
                  self.user, self.nice = [], []
                  self.l_user, = self.ax.plot([], self.user, label='Voltage')
                  self.l_nice, = self.ax.plot([], self.nice, label='Voltage2')
                  
                  # force a redraw of the Figure
                  self.fig.canvas.draw()
          
                  self.result1 = 0
                  self.result2 = 0
                  
                  self.action1()
          
              def action1(self):
                  self.result1 = 0.2
                  QtCore.QTimer.singleShot(1000, self.action2)
                  
              def action2(self):
                  self.result2 = 0.3
                  
                  self.user.append(self.result1)
                  self.nice.append(self.result2)
              
                  self.l_user.set_data(range(len(self.user)), self.user)
                  self.l_nice.set_data(range(len(self.nice)), self.nice)
              
                  # force a redraw of the Figure
                  self.fig.canvas.draw()
                  FigureCanvas.updateGeometry(self)
          
                  #envoie de l'évènement ici        
          
                  QtCore.QTimer.singleShot(1000, self.action1)
          
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            17 décembre 2011 à 1:01:52

            Il me semble qu'il y a aussi QEventLoop

            • Partager sur Facebook
            • Partager sur Twitter
              19 décembre 2011 à 11:34:12

              Salut,

              Merci beaucoup. J'ai essayé le code et tout marche bien! Comment puis-je faire si je ne veux pas "attendre" c'est à dire lancer l'action suivante à la fin de l'action. Ca marche très bien avec
              QtCore.QTimer.singleShot(0, self.action1) mais je sais pas si c'est très propre et très optimisé?

              Merci encore,

              Fabien
              • Partager sur Facebook
              • Partager sur Twitter
                20 décembre 2011 à 3:20:37

                Si tu n'as plus qu'une action, il faut qu'un timer.

                class CPUMonitor(FigureCanvas):
                    def __init__(self,parent):
                
                       
                        self.fig = Figure()
                        self.ax = self.fig.add_subplot(111)   
                        FigureCanvas.__init__(self, self.fig)       
                
                        # generates first "empty" plots
                        self.user, self.nice = [], []
                        self.l_user, = self.ax.plot([], self.user, label='Voltage')
                        self.l_nice, = self.ax.plot([], self.nice, label='Voltage2')
                        
                        # force a redraw of the Figure
                        self.fig.canvas.draw()
                
                        self.result1 = 0
                        self.result2 = 0
                        
                        self.startTimer(1000)
                
                    def timerEvent(self):
                        self.result1 = 0.2
                        self.result2 = 0.3
                        
                        self.user.append(self.result1)
                        self.nice.append(self.result2)
                    
                        self.l_user.set_data(range(len(self.user)), self.user)
                        self.l_nice.set_data(range(len(self.nice)), self.nice)
                    
                        # force a redraw of the Figure
                        self.fig.canvas.draw()
                        FigureCanvas.updateGeometry(self)
                
                        #envoie de l'évènement ici        
                
                        QtCore.QTimer.singleShot(1000, self.action1)
                


                pour ce qui est de la propreté, je trouve cela toujours mieux qu'une boucle infinie.
                pour l'optimisation, tu n'as pas à t'en soucier si tu fais une action par seconde. Il faut juste faire attention que ton action ne dure pas plus d'une seconde à s'exécuter.
                • Partager sur Facebook
                • Partager sur Twitter
                  20 décembre 2011 à 10:47:32

                  Salut Niko, merci beaucoup. En fait j'ai mal posé ma question. Il faut parfois que j'attende avant de lancer la commande suivante, parfois que lance la suivante "Le plus rapidement possible". Je met le code en dessous. C'est exactement le même que le tiens mis à part que le dernier Timer attend "0 secondes" avant de relancer action1. N'y a t'il pas une autre commande qui permette juste de dire "exécute telle def" et non pas "exécute telle def dans 0 secondes"?

                  class CPUMonitor(FigureCanvas):
                      def __init__(self,parent):
                  
                         
                          self.fig = Figure()
                          self.ax = self.fig.add_subplot(111)   
                          FigureCanvas.__init__(self, self.fig)       
                  
                          # generates first "empty" plots
                          self.user, self.nice = [], []
                          self.l_user, = self.ax.plot([], self.user, label='Voltage')
                          self.l_nice, = self.ax.plot([], self.nice, label='Voltage2')
                          
                          # force a redraw of the Figure
                          self.fig.canvas.draw()
                  
                          self.result1 = 0
                          self.result2 = 0
                          
                          self.action1()
                  
                      def action1(self):
                          self.result1 = 0.2
                          QtCore.QTimer.singleShot(1000, self.action2)
                          
                      def action2(self):
                          self.result2 = 0.3
                          
                          self.user.append(self.result1)
                          self.nice.append(self.result2)
                      
                          self.l_user.set_data(range(len(self.user)), self.user)
                          self.l_nice.set_data(range(len(self.nice)), self.nice)
                      
                          # force a redraw of the Figure
                          self.fig.canvas.draw()
                          FigureCanvas.updateGeometry(self)
                  
                          #envoie de l'évènement ici        
                  
                          QtCore.QTimer.singleShot(0, self.action1)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    20 décembre 2011 à 15:07:06

                    As tu essayé en appelant directement self.action1()?
                    Je pense que dès que tu utilises le timer Qt exécute tes actions dans un thread séparé.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 décembre 2011 à 15:13:53

                      Salut,

                      Merci beaucoup, j'avais oublié les parenthèses après self.action1. Ca marche nickel!
                      • Partager sur Facebook
                      • Partager sur Twitter

                      [Qt+Python]Lancer l'affichage dans boucle while

                      × 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