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

Python Discussion :

timer pour QCM avec réponse en temps imparti


Sujet :

Python

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut installer un timer pour gérer un questionnaire avec réponse en temps imparti
    Bonjour à tous,

    Pour mon premier post, je rentre d'emblée dans un sujet difficile (pour moi). J'utilise Python 2.6 sous XP : un gros point noir pour moi dans l'utilisation de Python : la compréhension et donc la constitution de classes.
    Mais je m'éloigne un peu de mon sujet : on a sollicité de ma part une aide que je me retrouve incapable de fournir.
    Une de mes connaissances a établi un petit programme en Python sans appel à un quelconque GUI (tkinter ou autre) un petit programme qui fonctionne.
    Il a établi une série de questions sur la 1ere déclinaison latine et une série de réponses correspondantes.
    12 questions sont tirées au sort de façon à ce que 2 fois la même question dans une série ne soit pas posée...
    Les réponses son traitées : Vrai -Faux et un bilan établi au terme de la série de questions.
    Ce programme fonctionne tel quel même s'il est grandement améliorable au niveau code...
    L'os sur lequel je bute est l'ajout d'un temps imparti pour répondre à la question et en cas de délai dépassé, arrêt du timer, génération d'une nouvelle question et redémarrage du timer.
    Après recherche je suis tombé sur ce code de guigui : http://python.developpez.com/faq/ind...ad#ThreadTimer
    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
    # -*- coding: cp1252 -*-
    import threading
    import time
     
     
    class MyTimer:
        def __init__(self, tempo, target, args= [], kwargs={}):
            self._target = target
            self._args = args
            self._kwargs = kwargs
            self._tempo = tempo
     
        def _run(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
            self._target(*self._args, **self._kwargs)
     
        def start(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
     
        def stop(self):
            self._timer.cancel()
     
     
    def affiche(unstr):
        print unstr, time.clock()
     
    a = MyTimer(1.0, affiche, ["MyTimer"])
    a.start()
    time.sleep(5.5)
    print u"Timer arrêté"
    a.stop()
    time.sleep(2.0)
    print u"Timer relancé"
    a.start()
    Ce code étant opérationnel, s'est posée la question de son adaptation aux besoins de la problématique.
    J'ai essayé de procéder comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    a = MyTimer(1.0, scrute, ["Temps :"])
    a.start()
    ReponseUtilisateur=raw_input("Entrez votre réponse : ")
    J'ai modifié le def affiche(unstr) de guigui en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def scrute(Stop):
        temps = int(time.clock())
        if temps > 5 :
            print "Délai dépassé !"
            a.stop()
    Le timer ne démarre qu'après avoir donné la réponse : là si j'attends 5 s, le message Délai dépassé apparaît.
    Tout se passe donc comme si le raw_input bloquait le lancement du timer.
    Il faudrait donc que fonctionnement du timer et le déroulement du programme se fasse dans 2 processus différents, non ?
    Je n'ai donc finalement rien compris au fonctionnement de la classe Mytimer de guigui. Et on en revient à ce que je disais au début sur la compréhension des classes...
    Je ne vois pas comment, dans l'état actuel de mes connaissances, je peux m'en sortir : je suis ouvert à toute suggestion, mercuriale, critique...

    Merci d'avance

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bien le bonjour à tous,

    Sauf pour moi qui, n'ayant pas de réponse, les jours ne sont pas bons...
    J'ai modifié l'intitulé de mon 1er message :
    - il n'était peut-être pas assez explicite,
    - il ne s'agissait pas d'un QCM, mais d'un questionnaire "à choix unique" (néologisme)
    Je n'ai pas avancé d'un pouce : quoi que je fasse, le raw_input bloque le fonctionnement du timer et je ne vois pas de solution pour contourner ce problème...
    En fait, si j'ai un peu avancé, mais ce n'est pas satisfaisant, ce n'est qu'un contournement :
    - je prends le temps juste après que la question est posée debut=time.time()
    - je prends le temps juste après que la question est donnée fin=time.time()
    - je calcule le temps écoulé,
    - s'il est supérieur au temps imparti, je signale que la réponse n'est pas prise en compte comme hors délai et j'enchaîne sur la question suivante...
    Mais j'aurais voulu que le message apparaisse avant la réponse si celle-ci est hors délai...

    Vous n'allez quand même pas me dire que mon sujet n'a pas de réponse : j'ai vu sur ce forum des réponses à des sujets qui me semblaient bien plus complexes encore ?
    Peut-être, la bonne personne n'est-elle pas encore passée ? J'attendrai donc patiemment...

    Merci aux bonnes âmes qui m'ont lu, à celles qui me liront et à celles qui me répondront !

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    76
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2008
    Messages : 76
    Points : 94
    Points
    94
    Par défaut
    Salut !

    J'ai repris le code que tu donnes et ça me semble bien marcher pourtant. Peut-être n'ai-je pas compris ce que tu cherches à faire. Si je lance le script ci-dessous, j'ai tout d'abord l'affichage du texte "Entrez votre réponse" puis, si j'attends plus de 5 secondes, "Délai dépassé" est affiché et le timer stoppé.


    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
    # -*- coding: cp1252 -*-
    import threading
    import time
     
     
    class MyTimer:
        def __init__(self, tempo, target, args= [], kwargs={}):
            self._target = target
            self._args = args
            self._kwargs = kwargs
            self._tempo = tempo
     
        def _run(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
            self._target(*self._args, **self._kwargs)
     
        def start(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
     
        def stop(self):
            self._timer.cancel()
     
     
    def affiche(unstr):
        temps = int(time.clock())
        if temps > 5 :
            print "Délai dépassé !"
            a.stop()
     
     
    a = MyTimer(1.0, affiche, ["MyTimer"])
    a.start()
     
    reponse = raw_input("Entrez votre réponse : ")
    a.stop()
    print "Vous avez répondu : " + reponse

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    Août 2004
    Messages
    723
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 723
    Points : 923
    Points
    923
    Par défaut
    Il faut que tu synchronises les deux threads :
    - Si l'utilisateur répond à la question, arrêter le timer
    - Si le temps est écoulé, annuler la question et passer à la suivante

    Je te conseille de découpler l'entrée clavier du gestionnaire de questions, ça sera plus simple, en d'autres termes tu fais un thread séparé qui s'occupera de lire ce que l'utilisateur entre, et qui le signale au gestionnaire de questions, étant donné qu'à ma connaissance on ne peut pas facilement annuler un raw_input.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bonjour,

    Et merci...
    Je n'ai pas été clair donc je reprends.
    Il y a bien affichage de : Entrez votre réponse avec un curseur clignotant.
    Je voudrais que, en l'absence de réponse de ma part dans le délai imparti, il y ait arrêt du timer et affichage du message...
    Or, là, avec ce script, je peux passer 10 min à attendre avant de donner la réponse, il ne se passe rien.
    Par contre, oui dans ce cas, dès que je réponds alors le message (et pas qu'un exemplaire !) s'affiche : mais dans ce cas c'est prendre un canon pour se défaire d'un moustique, ma solution de "contournement marche aussi bien, en moins lourd.

    Ta réponse confirme ce que je pensais ; 2 threads différents l'un pour le timer l'autre pour la gestion de la réponse et du raw_input, mais ça, hélas, mes connaissances actuelles ne me permettent pas de le faire : je suis totalement incompétent à la matière... Tant pis.

    Merci encore quand même, mais je continue à espérer...

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bonsoir,

    Personne n'a d'idée...
    Par acquit de conscience j'ai repris le code dont clic4 dit qu'il fonctionne chez lui (copier/coller)...
    Chez moi, tant que je ne donne pas la réponse qu'attend le raw_input, le curseur clignote...
    Dès que je donne une réponse, l'affichage se fait : délai dépassé et probablement en autant de fois que delai d'attente/5 puisque la réponse doit intervenir dans les 5 s.
    Il faudrait que je crée une classe pour attendre/gérer la réponse ?
    J'appelle la classe MyTimer, je pose la question, puis j'appelle la classe MaReponse où je récupère la réponse et je gère vrai/faux et je rends la main à la boucle principale avec une variable True/False pour la comptabilisation...
    Comme ça ça marcherait ?
    Mon problème : je n'ai encore jamais créé de classes et je doute fort d'y arriver (et ce n'est pas de la mauvaise volonté !), pour mes débuts, dans ce prog...
    Donc je renouvelle mon appel à l'aide...

    Merci d'avance à tous...

    PS
    Guigui, toi qui es l'auteur de ce timer, si tu passes par là, t'auras bien une idée ???

  7. #7
    Expert éminent sénior
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Points : 10 067
    Points
    10 067
    Par défaut
    Effectivement, le problème, je pense va venir du raw_input parce que je ne sais pas comment le tuer. Il existe cependant un module SendKeys très facile d'utilisation que tu peux télécharger ici : http://www.rutherfurd.net/python/sendkeys/
    Ce module permet de simuler l'appui de touche du clavier (donc ici la touche Entrée pour que le raw_input se termine).
    Sinon, il faut partir avec l'idée de oiffrig

    Voici un exemple complet de ce que je pense tu souhaites. Attention, c'est très mal programmé (donc, il faudra le réécrire )

    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
    # -*- coding: cp1252 -*-
    import threading
    import time
    import sys
    import SendKeys
     
     
    class MyTimer:
        def __init__(self, tempo, target, args= [], kwargs={}):
            self._target = target
            self._args = args
            self._kwargs = kwargs
            self._tempo = tempo
     
        def _run(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
            self._target(*self._args, **self._kwargs)
     
        def start(self):
            self._timer = threading.Timer(self._tempo, self._run)
            self._timer.start()
     
        def stop(self):
            self._timer.cancel()
     
    def scrute(Stop):
        temps = int(time.clock())
        if temps > 5 :
            print "Délai dépassé !"
            b.stop()
     
    class Reponse(threading.Thread):
        def __init__(self, myTimer):
            threading.Thread.__init__(self, None, self._run)
            self.myTimer = myTimer
            self.reponse = None
     
        def _run(self):
            self.reponse = raw_input("Entrez votre réponse : ")
            self.myTimer.stop()
            print u"Votre réponse :", self.reponse
     
        def start(self):
            super(Reponse, self).start()
            self.myTimer.start()
     
        def stop(self):
            SendKeys.SendKeys("{ENTER}")
            self.reponse = u"Pas de réponse"
            print self.reponse
     
    a = MyTimer(1.0, scrute, ["Temps :"])
    b = Reponse(a)
    b.start()

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bonjour,

    Merci guigui : je vais tâcher de comprendre les interactions de tes deux classes : l'une hérite de l'autre c'est bien ça ?
    Tous ces self.qq ch me perturbent : il faut que je trouve aussi une doc m'expliquant à quoi ça sert...

    Je vois que ce module SendKeys sert à bien d'autres choses ; je vais regarder ça de plus près.

    Bon, hélas, après test de ton script tel quel, indépendamment du programme dans lequel je veux l'insérer, il ne marche pas plus que le précédent, c'est à dire que la simulation d'appui sur ENTREE par le biais de SendKeys ne fait pas avancer le schmilblick : le raw_input garde la main tant que je n'ai pas appuyé sur ENTREE.
    Nota : J'utilise Python 2.6 (sous XP Sp2) avec la version ad hoc de SendKeys.

    Il devrait être possible de se passer de ce raw_input, pour récupérer la réponse, via une scrutation des appuis sur le clavier avec des events, non ?
    Je pense à une boucle de récupération des appuis sur une touche quelconque du clavier, boucle de laquelle on sort par ENTREE :
    Pseudo-code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    rp=""
    while not rp==chr(13):
         rcp = récupération des appuis sur une touche quelconque
         print rcp,
         Reponse+= rcp
    Si oui, je vais me pencher, sur cette gestion des events,
    Quand je programmais en BASIC compilé, je déclenchais le timer n° x intégré et j'écrivais :
    a$=""
    rep$=""
    while not a$=chr$(13):
    a$=inkey$
    rep$=rep$+a$
    test du timer et déroutage possible
    wend

    Un tel bricolage est-il possible en Python ?

    Merci d'avance

    PS
    Citation Envoyé par oiffrig
    Je te conseille de découpler l'entrée clavier du gestionnaire de questions, ça sera plus simple, en d'autres termes tu fais un thread séparé qui s'occupera de lire ce que l'utilisateur entre, et qui le signale au gestionnaire de questions,
    Ce n'est pas ce qui est fait là avec les deux classes ? Si la réponse est non, alors, je ne comprends pas la différence entre ce que tu me proposes et l'idée d'oiffrig...

  9. #9
    Expert éminent sénior
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Points : 10 067
    Points
    10 067
    Par défaut
    Je ne comprends pas pourquoi ce ne marche pas chez toi.
    Quand je lance le prog et que je ne fais rien d'autres voilà le résultat:
    (a.py étant le prog que j'ai posté plus haut)

    D:\Python>c:/python25/python.exe a.py
    Entrez votre rÚponse : DÚlai dÚpassÚ !

    Votre réponse :
    Pas de réponse

    D:\Python>pause
    Appuyez sur une touche pour continuer...

  10. #10
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Question qui s'étend au delà du langage Python:
    est-ce qu'il n'existe pas une possibilité en informatique de faire surveiller en permanence par un ordinateur ce qui est tapé au clavier et de le lui faire détecter sans même qu'il y ait eu frappe de la touche 'Enter' ?
    C'est à dire que dès qu'une touche serait appuyée, hop, l'ordinateur en est informé, prend en charge l'information (le caractère) entré et la traite: dans l'idée que j'ai des ordinateurs, selon laquelle ils sont capables de faire une variété de choses sidérante, je me dis que ce serait bien étonnant que cette possibilité n'existe pas. Peut être pourrait on appeler ça du 'streaming input" ? Est-ce que ce n'est pas ce que font les keyloggers ?
    Si ça existe, ça devrait permettre de répondre au problème en testant en boucle l'état du buffer de streaming input.
    Do you see what I mean ?
    Est-ce que je fais de la science informatique fiction ?

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    Points : 67
    Points
    67
    Par défaut
    Bonjour,

    Merci...
    J'ai trouvé pourquoi il ne marche pas. ; j'ai d'abord désinstallé 2.6 pour remettre le 2.5 : pas de changement.
    C'est alors que j'ai eu l'oeil attiré par ce que tu as écrit : tu as essayé en mode console pas avec l'idle de python : là effectivement ça marche !
    Et ça ne marche pas "sous windows", pourquoi ?

    Cordialement

  12. #12
    Expert éminent sénior
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Points : 10 067
    Points
    10 067
    Par défaut
    IDLE et les thread ne font pas bon ménage.
    IDLE ajoute une surcouche en Tkinter et il peut y avoir des interférences avec l'utilisation de thread.

Discussions similaires

  1. Réponses: 0
    Dernier message: 11/01/2011, 11h17
  2. Réponses: 27
    Dernier message: 23/05/2008, 02h18
  3. creer une page avec timer pour 2 URLS
    Par anubisme dans le forum Langage
    Réponses: 4
    Dernier message: 21/04/2006, 11h03
  4. Hebergeur mutilialisé avec mysql et temps de réponse
    Par dreck dans le forum Requêtes
    Réponses: 7
    Dernier message: 06/02/2006, 08h51
  5. Réponses: 4
    Dernier message: 24/11/2005, 08h34

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