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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 éprouvé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    76
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2008
    Messages : 76
    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 émérite

    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
    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 confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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 confirmé
    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 : 44
    Localisation : France, Saône et Loire (Bourgogne)

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

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    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 Expert
    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
    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 ?

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 105
    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

  10. #10
    Expert confirmé
    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 : 44
    Localisation : France, Saône et Loire (Bourgogne)

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

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    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