Skip to Content

Python et QT (tutoriel 7)

Dans le tutoriel précédent, nous avons révisé nos connaissances sur l’IDE Eric en créant une petite application qui manipulait une barre de progression avec un timer. Nous allons utiliser ces élements pour compléter l’application que nous avons commencé dans le tutoriel 5.

Éléments abordés dans ce document

  •  L’evaluation d’expression « avec eval() »
  •  Les afficheurs LCD de QT « avec display() »
  •  L’affichage de boîte de dialogue « avec QMessageBox.information() »
  •  Des propriétés supplémentaires associées aux widgets QT « avec setReadOnly(), setFocus() »
  •  Le module time « avec time() »

    Au travail

    On rajoute la fonction NouveauNombres() à notre classe MainForm_Impl. Celle-ci va tirer des nombres au hasard en respectant les limites imposées pour l’exercice. Elle se charge également de l’affichage et des modifications des zones de saisie.

    Cette fonction sera appelée une première fois par la fonction StartSlot() et ensuite par la fonction TestReponseSlot() jusqu’à la fin de l’exercice.

    La fonction StartSlot() est appelée lorsque l’utilisateur clique sur le bouton qui permet de commencer l’exercice. Elle est chargée d’initialiser les paramètres liés à l’exercice et notamment le timer qui va rythmer le tout.

    La fonction TestReponseSlot() est appelée à chaque fois que l’utilisateur valide une réponse ou lorsque la barre de progression arrive à 0. Elle vérifie la réponse, met à jour les compteurs et relance une nouvelle question si l’exercice n’est pas terminé.

    Ce qui nous donne le code suivant :


    class MainForm_Impl(MainForm):
       op1=0                        #la valeur du 1er opérande
       op2=0                        #la valeur du 2nd opérande
       resultat=0                  #la valeur du résultat
       debutExercice=0.0   #pour calculer la durée de l'exercice

       def __init__(self,parent = None,name = None,modal = 0,fl = 0):
           MainForm.__init__(self,parent,name,modal,fl)

           self.timer=QTimer(self)
           self.connect(self.timer, SIGNAL('timeout()'), self.TimeOutSlot)

    # public slot

       def init(self):
           items=[]
           items.append(QListViewItem(self.ExerciseListView,"Additions"))
           items.append(QListViewItem(self.ExerciseListView,"Divisions"))
           items.append(QListViewItem(self.ExerciseListView,"Multiplications"))
           items.append(QListViewItem(self.ExerciseListView,"Soustractions"))

           try:
               fsock = open('exercices.txt')
               try:
                   dataLines = [line for line in fsock.readlines() if line[0]!='#']
               finally:
                   fsock.close()
           except IOError:
               pass
           try:
               for dataLine in dataLines:
                   exercice, oorq, delai, question = re.findall("^([^\\t]+)\\t+([^\\t]+)\\t+(\\d+)\\t+(\\d+)",dataLine)[0]
                   op1Min, op1Max, q1, operateur, op2Min, op2Max, q2, max, q3 = re.findall("^\\[([0-9]{1,3})..([0-9]{1,3})\\](_?)([+\\-*/])\\[([0-9]{1,3})..([0-9]{1,3})\\](_?)<=([0-9]{1,3})(_?)$", oorq)[0]
                   items.append(QListViewItem(items[['+', '/', '*', '-'].index(operateur)], unicode(exercice,'utf8'), oorq, delai, question))
           except NameError:
               pass

       def TestReponseSlot(self):
           if self.timer.isActive(): self.timer.stop()
           
           if self.operande1LineEdit.text().ascii()==''     \
           or self.operande2LineEdit.text().ascii()==''   \
           or self.resultatLineEdit.text().ascii()==''         \
           or eval(self.operande1LineEdit.text().ascii()+self.operateur.text().ascii()+self.operande2LineEdit.text().ascii()) <> eval(self.resultatLineEdit.text().ascii()):
               self.WrongLCDNumber.display(self.WrongLCDNumber.intValue()+1)
               QMessageBox.information(self,'', unicode('Voici la bonne réponse :\n'+`self.op1`+' '+self.operateur.text().ascii()+' '+`self.op2`+' = '+`self.resultat`,'utf8'))
               #TODO : mémoriser les paramètre de la question pour la reposer à  la fin de l'exercice
           else:
               self.GoodLCDNumber.display(self.GoodLCDNumber.intValue()+1)
           self.TotalLCDNumber.display(self.TotalLCDNumber.intValue()+1)

           if self.TotalLCDNumber.intValue() >= int(self.CountLineEdit.text().ascii()) or not NouveauxNombres(self):
               self.StartPushButton.setEnabled(1)
               QMessageBox.information(self,'', unicode('Exercice terminé en %d secondes' % int(time.time()-self.debutExercice),'utf8'))
           else:
               self.DelaiProgressBar.setProgress(int(self.DelaiLineEdit.text().ascii())*100)
               self.timer.start(10)

       def StartSlot(self):
           self.StartPushButton.setEnabled(False)
           NouveauxNombres(self)
           self.DelaiProgressBar.setTotalSteps(int(self.DelaiLineEdit.text().ascii())*100)
           self.DelaiProgressBar.setProgress(int(self.DelaiLineEdit.text().ascii())*100)
           self.operateur.setText(['*', '+', '-', '/'][self.OperateurComboBox.currentItem()])
           self.TotalLCDNumber.display(0)
           self.GoodLCDNumber.display(0)
           self.WrongLCDNumber.display(0)
           self.timer.start(10)
           self.debutExercice=time.time()

       def TimeOutSlot(self):
           p = self.DelaiProgressBar.progress()
           if  p > 0 :
               self.DelaiProgressBar.setProgress(p-1)
           else:
               self.TestReponseSlot()

       def SelectExerciseSlot(self):
           exercise=self.ExerciseListView.currentItem().text(1).ascii()
           if exercise:
               op1Min, op1Max, q1, operateur, op2Min, op2Max, q2, max, q3 = re.findall("^\\[([0-9]{1,3})..([0-9]{1,3})\\](_?)([+\\-*/])\\[([0-9]{1,3})..([0-9]{1,3})\\](_?)<=([0-9]{1,3})(_?)$", exercise)[0]
               self.MinOp1LineEdit.setText(op1Min)
               self.MaxOp1LineEdit.setText(op1Max)
               self.OperateurComboBox.setCurrentItem(['*', '+', '-', '/'].index(operateur))
               self.MinOp2LineEdit.setText(op2Min)
               self.MaxOp2LineEdit.setText(op2Max)
               self.ResultatMaxLineEdit.setText(max)
               self.PositionLineEdit.setText(`(q1=='_')+(q2=='_')*2+(q3=='_')*4`)
               self.CountLineEdit.setText(self.ExerciseListView.currentItem().text(3).ascii())
               self.DelaiLineEdit.setText(self.ExerciseListView.currentItem().text(2).ascii())
           else:
               operateur=self.ExerciseListView.currentItem().text(0).ascii()
               self.OperateurComboBox.setCurrentItem(['Multiplications', 'Additions', 'Soustractions', 'Divisions'].index(operateur))
       
    def NouveauxNombres(self, revision=0):
       "Initialise les données pour une nouvelle question."
       op1min=int(self.MinOp1LineEdit.text().ascii())
       op1max=int(self.MaxOp1LineEdit.text().ascii())
       op2min=int(self.MinOp2LineEdit.text().ascii())
       op2max=int(self.MaxOp2LineEdit.text().ascii())
       resultatMax=int(self.ResultatMaxLineEdit.text().ascii())
       operation=('*', '+', '-', '/')[self.OperateurComboBox.currentItem()]
       posQuestion=int(self.PositionLineEdit.text().ascii())
       
       if revision:
           QMessageBox.information( 0, "Révision", "Révisions terminées")
           return 0
       else:
           if operation=='/':
               while 1:
                   self.op2 = random.randint(op2min, op2max)
                   self.resultat = random.randint(0,resultatMax)
                   self.op1 = self.resultat*self.op2
                   if self.op1>=op1min and self.op1 <= op1max: break
           else:
               while 1:
                   self.op1 = random.randint(op1min, op1max)
                   self.op2 = random.randint(op2min, op2max)
                   self.resultat = eval(str(self.op1) + operation + str(self.op2))
                   if self.resultat>=0 and self.resultat <= resultatMax: break

       if posQuestion == 1:            posTrou=0
       elif posQuestion == 2:        posTrou=1
       elif posQuestion == 3:        posTrou=random.randint(0,1)
       elif posQuestion == 4:        posTrou=2
       elif posQuestion == 5:       
           if random.randint(0,1):posTrou=2
           else:                              posTrou=0
       elif posQuestion == 6:        posTrou=random.randint(1,2)
       elif posQuestion == 7:        posTrou=random.randint(0,2)

       if posTrou==0:            # op1
           self.operande1LineEdit.setText("")
           self.operande1LineEdit.setReadOnly(0)
           self.operande2LineEdit.setText(`self.op2`)
           self.operande2LineEdit.setReadOnly(1)
           self.resultatLineEdit.setText(`self.resultat`)
           self.resultatLineEdit.setReadOnly(1)
           self.operande1LineEdit.setFocus()
       elif posTrou==1:            # op2
           self.operande1LineEdit.setText(`self.op1`)
           self.operande1LineEdit.setReadOnly(1)
           self.operande2LineEdit.setText("")
           self.operande2LineEdit.setReadOnly(0)
           self.resultatLineEdit.setText(`self.resultat`)
           self.resultatLineEdit.setReadOnly(1)
           self.operande2LineEdit.setFocus()
       elif posTrou==2:    #resultat
           self.operande1LineEdit.setText(`self.op1`)
           self.operande1LineEdit.setReadOnly(1)
           self.operande2LineEdit.setText(`self.op2`)
           self.operande2LineEdit.setReadOnly(1)
           self.resultatLineEdit.setText("")
           self.resultatLineEdit.setReadOnly(0)
           self.resultatLineEdit.setFocus()    
       return 1

    Si vous lancez l’application, vous devriez obtenir ceci :


    Pour la suite, c’est ici

    Historique des modifications

    Version Date Commentaire
    0.1 03/04/2006 Création par Jibux
    0.2 26/11/2006 Ajout d’un lien vers l’article suivant
    Zip - 45 ko
    Les fichiers sources de cette application
  • Fichier attachéTaille
    revcal.jpg28.2 Ko
    Les fichiers sources de cette application45 Ko

    Commentaires

    > Python et QT (tutoriel 7)

    Merci pour ta relecture

    > Python et QT (tutoriel 7)

    RAS :o)