coagul : Python et QT (tutoriel 7)

Créé par Jean-Emmanuel Bissey le 07/11/2025 modifié le 08/11/2025 Publié

Rubrique : Programmation

Le : dimanche 9 avril 2006

Par : jibux 

Visites : 2553

Tags : Python, QT

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

Galerie