Zeitlich Begrentzte Eingabe

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Boggel
User
Beiträge: 23
Registriert: Samstag 15. Dezember 2018, 12:56

Hallo,

ich bin neu in diesem Forum und in der Sprache Python.
Ich wollte ein kleines Programm schreiben in dem man ein zeitlich bregrenzte Eingabe hat.
Also einen input der z.B. nach 5 Sekunden abricht und dann das Programm weitermacht.
Ist dies möglich? Wenn ja bitte ich um Antwort.

Mfg Nils
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wo willst du das denn machen? Auf der Kommandozeile oder als grafisches Programm?
Boggel
User
Beiträge: 23
Registriert: Samstag 15. Dezember 2018, 12:56

Auf der Kommandozeile.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Das hängt vom System ab, auf dem das laufen soll. Unter *nix einfach per `select`:

Code: Alles auswählen

import sys
import select

print("Du hast 5s Zeit, die Antwort zu geben:")
if select.select([sys.stdin],[],[], 5)[0]:
    value = input()
else:
    print("Zu spät")
Boggel
User
Beiträge: 23
Registriert: Samstag 15. Dezember 2018, 12:56

@Sirius3
Ich speichere das immer unter dem File .py ab um es dann unter windows 10 in der Kommandozeile zu starten.
Dein Vorschlag mit dem Code hat leider nicht funktioniert.
Die Fehlermeldung lautet: OSError: [WinError 10093] Die Anwendung hat die Funktion WSAStartup nicht aufgerufen, oder bei dieser Funktion ist ein Fehler aufgetreten
Kannst du mir da weiterhelfen?
Benutzeravatar
__blackjack__
User
Beiträge: 13007
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Boggel: Windows ist halt kein *nix. ;-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Boggel
User
Beiträge: 23
Registriert: Samstag 15. Dezember 2018, 12:56

@_blackjack_
In unserer Familie gibt es zwar noch einen C64 aber was hilft mir das bei meiner Python Programmierung.
Ich will ja eben wissen wie ich die Zeitlich begrentzte EIngabe unter Python programmieren kann.
Benutzeravatar
__blackjack__
User
Beiträge: 13007
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du willst wissen wie Du eine zeitlich begrenzte Eingabe unter Python *unter Windows* programmieren kannst. Das läuft dann aber nicht unter *nix-Systemen. So wie die Lösung von Sirius3 für *nix-Systeme eben nicht für Windows-Systeme funktioniert.

Falls es für Dein Problem keine plattformübergreifende Lösung in Form einer fertigen Bibliothek gibt, würde ich das ja ganz sein lassen. Als GUI-Programm ginge es plattformübergreifend. Bei Tkinter würde man zum Beispiel mit der `after()`-Methode einfach eine Rückruffunktion/-methode registrieren, die nach der definierten Zeit das Eingabefeld und gegebenfalls die Schaltfläche zur Bestätigung der Eingabe deaktiviert.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Noch als Ergaenzung: Windows macht einem die Arbeit mit der Konsole nicht so einfach. Darum hat Python die notwendigen Mittel nicht an Bord, um dein Problem zu loesen. Was du brauchst ist "WaitForSingleObject" oder "WaitForMultipleObjects". AFAIK kommst du an die nur entweder mit Dritt-Modulen, oder per ctypes und selbst gewrappter win32-API. Und fuer keines von beiden habe ich fertige Beispiele gefunden.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

während `select` unter *nix wartet, bis eine ganze Zeile eingegeben wurde, wartet WaitForSingleObject nur auf den ersten Tastendruck.

Code: Alles auswählen

import win32api
import win32event

stdin = win32api.GetStdHandle(-10)
if win32event.WaitForSingleObject(stdin, 1000):
    print("Timeout")
else:
    print("Taste gedrückt")
wenn man also in einer bestimmten Zeit eine ganze Zeile eingegeben haben will, muß man das selbst noch über eine Zeitmessung machen, also auf einen Tastendruck warten, über ReadConsole ein einzelnes Zeichen lesen, Timeout-Zeit entsprechend anpassen und wieder warten.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich dachte mir, da könnte man doch auch was mit pygame machen.
Der feine win32api Code ist natürlich eleganter.
Aber es gibt wie immer viele Wege, die zum Ziel führen.

Code: Alles auswählen

#!/usr/bin/env python3
import os
from pygame.locals import *
from time import time
from pygame import init, display, event, quit


def main():
    os.environ['SDL_VIDEO_CENTERED'] = '1'
    init()
    display.set_caption('Innerhalb 5 Sekunden Text eingeben!')
    display.set_mode((400, 1))

    times_up = False
    pressed_keys = []
    start_time = time()
    while not times_up:
        for my_event in event.get():
            if my_event.type == KEYDOWN:
                pressed_keys.append(my_event.key)
                if my_event.key == K_ESCAPE:
                    pass
                if my_event.key == K_UP or event.key == K_w:
                    pass
                if my_event.key == K_p:
                    pass
        times_up = (time() - start_time) > 5.0
    quit()
    print(''.join([chr(key) for key in pressed_keys]))


if __name__ == '__main__':
    main()
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13007
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da sieht man den Text ja gar nicht. Und man muss auch beachten das hier alle möglichen Tasten ausser Buchstaben gedrückt werden können, die erfasst werden. Also da ist eine kleine GUI dann doch praktischer und weniger Aufwand. Tk ist Teil der Standardbibliothek, und man bekommt die Bearbeitung eines Eingabefeldes quasi umsonst, was man sich mit Pygame alles noch selbst programmieren müsste.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

hab's heute morgen mal unter Win ausprobiert, rein Interesse halber. Der folgende Code funktioniert:

Code: Alles auswählen

import msvcrt
import time
import sys

#Quelle: https://stackoverflow.com/questions/15528939/python-3-timed-input

class TimeoutExpired(Exception):
    pass

def eingabe_mit_timeout(prompt, timeout, timer=time.monotonic):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    endzeit = timer() + timeout
    eingabe = []
    while timer() < endzeit:
        if msvcrt.kbhit():
            eingabe.append(msvcrt.getwche())
            if eingabe[-1] == '\r':
                return ''.join(eingabe[:-1])
        time.sleep(0.04)
    raise TimeoutExpired

ereignisse = (('Wann endete der 30-jährige Krieg?', 1648),
              ('In welchem Jahr begann die französische Revolution?', 1789),
              ('Im welchem Jahr wurde Helmut Kohl Bundeskanzler?', 1982))

print('5 Sekunden pro Antwort')
time.sleep(1)
for zaehler, ereignis in enumerate(ereignisse, 1):
    print('{}. Frage'.format(zaehler))
    time.sleep(1)
    try:
        prompt = '{}\r\n'.format(ereignis[0])
        antwort = eingabe_mit_timeout(prompt, 5)
    except TimeoutExpired:
        print('Zu langsam...')
        print('Die Antwort wäre {} gewesen.'.format(ereignis[1]))
    else:
        if int(antwort) == ereignis[1]:
            print('Richtig!')
        else:
            print('Die Antwort ist leider falsch. Richtig ist: {}'.format(ereignis[1]))
    time.sleep(1)
Die Quelle, wo der Kern der Lösung herkommt, ist im Kommentar im Code vermerkt. Das Spielchen habe ich testweise drum rum gebaut, um das zu auszuprobieren.

Es gibt im Netz noch eine 2. Weg, das unter Win (bzw. Cross-Plattform) zu machen, mittels `threading.timer`. Wobei ich die Lösung mittels `select` bzw die obige für Win besser finde.

Gruß, noisefloor
Boggel
User
Beiträge: 23
Registriert: Samstag 15. Dezember 2018, 12:56

@noiseflorr
Danke der Code hat geklappt.
Hab ihn für mich abgeändert funktioniert alles.

Mfg Nils
Antworten