Seite 1 von 1

Stoppuhr in Python?

Verfasst: Donnerstag 27. Mai 2004, 20:26
von derMannUndDasMeer
Hallo,

mein Programm soll die Zeit von bestimmten Dingen stoppen.

Dafür habe ich eine Klasse "Timer" geschrieben. Leider läuft das Programm nur noch ruckelig ab, wenn ich das so mache. Ich komme aus der Java-Welt; dort gibt es für so etwas Threads. Wie löst man das Problem in Python?

Vielen Dank

Tobias

Code: Alles auswählen

class Timer:
    
    def __init__(self):
        self.seconds = 0
        self.active = False

    def start(self):
        self.seconds = 0        
        self.countSeconds()
        print "Starte Timer"

    def stop(self):
        self.active = False

    def countSeconds(self):
        self.active = True
        
        while self.active == True:
            print "in while schleife"
            time.sleep(1)
            self.seconds += 1
            print "Seconds: %i" % self.seconds
        wend

    def getSeconds(self):
        return self.seconds

Verfasst: Donnerstag 27. Mai 2004, 20:32
von Milan
Hi. Entweder du willst etwas grafisch haben, dann löst du das auch in Threads (Module thread und threading) oder du misst einfach die Zeit nach, indem du die Differenz zweier time.clock() - Werte ermittelst.

Alles klar oder etwas zu knapp?

Verfasst: Donnerstag 27. Mai 2004, 20:43
von Christopy
Würd ich evt. mit Timer machen. Sekunden in einer Schleife zählen halte ich eher für einen schlechten Plan. Damit legt man das Programm und diverse Resourcen lahm.

Verfasst: Donnerstag 27. Mai 2004, 20:50
von derMannUndDasMeer
danke Euch!

Verfasst: Donnerstag 27. Mai 2004, 20:50
von Milan
Hi. Sind Timer nicht für was anderes da? Die sind doch zum starten eines Prozesses in x sekunden, wobei das innerhalb der x sekunden auch abgebrochen werden kann. Also so eine countdown, oder nicht?

Verfasst: Donnerstag 27. Mai 2004, 21:35
von Christopy
Sorry, Milan. Du hast natürlich vollkommen Recht!
Hab das irgendwie komplett Mißverstanden! :roll:
Dachte eine Funktion sollte eine zeitlang gestoppt werden und dann neu ausgeführt werden.
In dem Fall ist antürlich Deine Zeitdifferenzenmethode imho das Mittel der Wahl.

Verfasst: Donnerstag 27. Mai 2004, 21:48
von derMannUndDasMeer
hallo,

ich brauche nochmal Hilfe, denn ich krieg nicht raus, wie ich mit Threads arbeiten muss.

Habe mal folgendes probiert:

Code: Alles auswählen

def countTime(self):
        thr = start_new_thread(self.countSecond())
        
def countSecond(self):
        self.active = True        
        sleep(10) # als Beispiel 10 sek
        self.incrSeconds()
Die 10 Sekunden werden aber nicht "nebenläufig" gemessen, sondern das ganze Programm steht für 10 Sekunden.

Sicher wäre es einfacher einfach die Startzeit zu messen und dann immer die Differenz zu ermitteln, aber ich brauche Thread später wohl auch noch (wenn ich erstmal Python begreife ;-))

gruß

Tobias

Verfasst: Freitag 28. Mai 2004, 08:47
von Milan
Hi. Bitte schreib Pythoncode immer in die Codetags des BBCodes, da somit die Einrückungen nicht verloren gehen (mehrere Lehrzeichen zeigt ein Browser nunmal nicht ohne Konvertierung an). Ich hab das oben bei dir mal erledigt, denk bitte die nächsten male daran.

So. Nun dein eigentliches Problem. Du bist schon auf die richtige Funktion gestoßen, mit der du das machen kannst. Mit start_new_thread kannst du eine Funktion in einem neuem Thread ausführen lassen.
start_new_thread( function, args[, kwargs])
Start a new thread and return its identifier. The thread executes the function function with the argument list args (which must be a tuple). The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).
Dazu geht man aber funktional vor und übergibt das Funktionsobjekt (also nur den Namen der Funktion). Du rufst dagegen die Funktion auf (die zwei Klammern hinter der Funktion), wodurch dein Programm erst 10 sek steht, da noch kein neuer Thread da ist und dann der Rückgabewert (hier None) übergeben wird. Schreib also einfach nur start_new_thread(self.countSecond).

Viel Spaß :wink:

Verfasst: Freitag 28. Mai 2004, 09:42
von derMannUndDasMeer
Hallo,

vielen Dank für Deine Hilfe

jetzt habe ich einen Thread

Code: Alles auswählen

def countTime(self):
        thr = start_new_thread(self.countSecond, ())
        
    def countSecond(self):
        self.active = True
       
        while self.active:            
           time.sleep(1)
           self.seconds += 1
           self.timeCountLbl["text"] = self.seconds
        wend
Die Schleife sollte solange laufen, wie self.active == True ist. Wenn ich das Fenster schließe, wird der Thread nicht automatisch mit unterbrochen. Wie kann ich das Ereignis "fensterschließtsich" behandeln?

gruß

Tobias

ähm, ich poste mal das Progrämmchen hier rein. Beim ausführen wird das Problem vielleicht klarer. Wenn ich irgendwas anders gemacht habe, als es in Python üblich ist, wären Verbesserungsvorschläge auch cool!

Code: Alles auswählen


from Tkinter import *
#from Tix import *
from tkFileDialog import *
from tkFont import Font
from thread import start_new_thread
import time


class TipperUI(Canvas):
    """
    UI Hauptklasse der Anwendung
    mal gucken, wie tk klappt ;-)
    """
    def __init__(self, master=None):        
        Canvas.__init__(self, master)
        self.pack({"fill": "both", "expand": True})       
        self.createWidgets()
        self.pointer = [1, 1]
        self.seconds = 0
        self.loc = 0.0
        self.thr = None
        self.shiftPressed = False
        self.altLPressed = False
        self.altRPressed = False
        self.keyCount = 0
        self.errorCount = 0
        self.active = False
        self.startTime = 0
        

    def createWidgets(self):
        """
        Komponenten erzeugen (Widgets)
        """
        # Fonts
        self.bigFont = Font(family="Arial", size=25)
        self.mediumFont = Font(family="Arial", size=12)
        
        # centerCan
        self.centerCan = Canvas(self)       
        self.centerCan.pack({"side": "left", "fill": "both", "expand": True})
        
        # eastCan
        self.eastCan = Canvas(self)        
        self.eastCan.pack({"side": "right", "fill": "y"})

        # outputTxt
        self.outputTxt = Text(self.centerCan)
        self.outputTxt["height"] = 5        
        self.outputTxt["font"] = self.mediumFont
        self.outputTxt.pack({"anchor": "nw", "fill": "both", "expand": 1})
        self.outputTxt.tag_config("ok", background="yellow", foreground="red");
        self.outputTxt.tag_config("nok", background="red", foreground="black");
        #self.outputTxt["state"] = "disabled"
        self.outputTxt["background"] = "lightgrey"

        # newsCan
        self.newsCan = Canvas(self.centerCan)
        self.newsCan.pack({"in": self.centerCan, "anchor": "center", "fill": "both"})
        #self.newsCan.config({"bg": "red"})

        # currLetterLblfr
        self.currLetterLblfr = LabelFrame(self.newsCan)
        self.currLetterLblfr["text"] = "nächster Buchstabe"
        self.currLetterLblfr.pack({"in": self.newsCan, "side": "left"})        
        # currLetterLbl
        self.currLetterLbl = Label(self.currLetterLblfr)
        self.currLetterLbl["font"] = self.bigFont
        self.currLetterLbl["text"] = ""
        self.currLetterLbl.pack({"anchor": "center", "fill": "both"})

        # mistakesLblfr
        self.mistakesLblfr = LabelFrame(self.newsCan)
        self.mistakesLblfr["text"] = "Fehler"
        self.mistakesLblfr.pack({"in": self.newsCan, "after": self.currLetterLblfr, "side": "left", "anchor": "w"})
        # mistakesLbl
        self.mistakesLbl = Label(self.mistakesLblfr)
        self.mistakesLbl["font"] = self.bigFont
        self.mistakesLbl["text"] = "0"
        self.mistakesLbl.pack({"anchor": "center", "fill": "both"})

        # countTypingLblfr
        self.countTypingLblfr = LabelFrame(self.newsCan)
        self.countTypingLblfr["text"] = "Anschläge"        
        self.countTypingLblfr.pack({"in": self.newsCan, "after": self.mistakesLblfr, "side": "left", "anchor": "w"})
        # countTypingLbl
        self.countTypingLbl = Label(self.countTypingLblfr)
        self.countTypingLbl["font"] = self.bigFont
        self.countTypingLbl["text"] = 0
        self.countTypingLbl.pack({"anchor": "center", "fill": "both"})

        # timeCountLblfr
        self.timeCountLblfr = LabelFrame(self.newsCan)
        self.timeCountLblfr["text"] = "Zeit"        
        self.timeCountLblfr.pack({"in": self.newsCan, "after": self.countTypingLblfr, "side": "left", "anchor": "w"})
        # timeCountLbl
        self.timeCountLbl = Label(self.timeCountLblfr)
        self.timeCountLbl["font"] = self.bigFont
        self.timeCountLbl["text"] = 0
        self.timeCountLbl.pack({"anchor": "center", "fill": "both"})

        # typesPerMinuteLblfr
        self.typesPerMinuteLblfr = LabelFrame(self.newsCan)
        self.typesPerMinuteLblfr["text"] = "Anschläge / Minute"        
        self.typesPerMinuteLblfr.pack({"in": self.newsCan, "after": self.timeCountLblfr, "side": "left", "anchor": "w"})
        # typesPerMinuteLbl
        self.typesPerMinuteLbl = Label(self.typesPerMinuteLblfr)
        self.typesPerMinuteLbl["font"] = self.bigFont
        self.typesPerMinuteLbl["text"] = "-"
        self.typesPerMinuteLbl.pack({"anchor": "center", "fill": "both"})
        
        # inputTxt
        self.inputTxt = Text(self.centerCan)
        self.inputTxt["height"] = 5
        self.inputTxt["font"] = self.mediumFont
        self.inputTxt.pack({"anchor": "sw", "fill": "both", "expand": 1})
        self.inputTxt.bind("<KeyPress>", self.inputTxt_keyPressed)
        self.inputTxt.bind("<KeyRelease>", self.inputTxt_keyReleased);
  
        # optionLblfr
        self.optionLblfr = LabelFrame(self.eastCan)
        self.optionLblfr["text"] = "Optionen"        
        self.optionLblfr.pack({"side": "right", "fill": "both"})

        # openBtn
        self.openBtn = Button(self.optionLblfr)
        self.openBtn["text"] = "Öffnen.."
        self.openBtn["command"] = self.openFile
        self.openBtn.pack({"side": "top"})
        
        # resetBtn
        self.resetBtn = Button(self.optionLblfr)
        self.resetBtn["text"] = "Reset"
        self.resetBtn["command"] = self.reset
        self.resetBtn.pack({"side": "left"})
        
        # quitBtn
        self.quitBtn = Button(self.optionLblfr)
        self.quitBtn["text"] = "Ende"
        self.quitBtn["command"] = self.quit
        self.quitBtn.pack({"side": "bottom"})


    def reset(self):
        self.active = False       
        
        self.timeCountLbl["text"] = 0
        self.seconds = 0
        
        self.inputTxt.delete(0.0, 100.100)

        self.outputTxt.tag_delete("nok", "ok" )
        
        
    def inputTxt_keyPressed(self, event):
        """
        Callbackfunktion, wird aufgerufen wenn im inputTxt
        ein Key gedrückt wurde.
        """
        # Timer starten
        if self.active == False:
            self.countTime();
            """
            self.startTime = int(time.clock())
            self.active = True
        now = int(time.clock())
        # Zeit anzeigen
        self.timeCountLbl["text"] = now - self.startTime
        print "%i - %i" % (now ,self.startTime)
        """
           
        if event.keysym == "Shift_L":
            self.shiftPressed = True
            return
        if event.keysym == "Shift_R":
            self.shiftPressed = True
            return
        if event.keysym == "Alt_R":
            self.altRPressed = True
            return
        if event.keysym == "Alt_L":
            self.altLPressed = True
            return
        if event.keysym == "Control_L":
            return ;# ignorieren
                  
        # keyCount incrementieren
        self.keyCount += 1
        self.countTypingLbl["text"] = self.keyCount
        
        key = self.keysym2String(event.keysym)
        pos = self.tipper.getPos()
        if self.tipper.checkKey(key):
            # richtig            
            self.loc = "%i.%i" % (pos["y"], pos["x"])           
            self.outputTxt.tag_add("ok", 1.0, self.loc )
        else:
            # falsch            
            nloc = "%i.%i" % (pos["y"], pos["x"])
            self.outputTxt.tag_add("nok", self.loc, nloc )
            # errorCount incrementieren
            self.errorCount += 1
            self.mistakesLbl["text"] = self.errorCount

        # Text ausrichten
        self.outputTxt.see("%i.%i" % (pos["y"]+1, pos["x"]))

        # nächsten Buchstaben anzeigen
        key = self.tipper.getNextChar()
        if key == "":
            # Ende
            self.stop()
        else:
            self.currLetterLbl["text"] = self.char2Key(key);
            
        
    def stop(self):
        self.active = False
        
    def inputTxt_keyReleased(self, event):
        """
        Callbackfunktion, wird aufgerufen wenn im inputTxt
        ein Key losgelassen wurde.
        """
        if event.keysym == "Shift_L":
            self.shiftPressed = False
            return
        if event.keysym == "Shift_R":
            self.shiftPressed = False
            return
        if event.keysym == "Alt_L":
            self.altLPressed = False
            return
        if event.keysym == "Alt_R":
            self.altRPressed = False
            return


    def countTime(self):
        self.thr = start_new_thread(self.countSecond, ())
        
    def countSecond(self):
        self.active = True
       
        while self.active:            
           time.sleep(1)
           self.seconds += 1
           #if self.timeCountLbl == None:
           #    self.active = False
           #    break
           try:
               self.timeCountLbl["text"] = self.seconds
               minutes = int(self.seconds/60)
               seconds = int(self.seconds - minutes*60.0)
               self.timeCountLbl["text"] = ('%02d:%02d' % (minutes, seconds))
           except Exception:
               self.active = False
               self.thr.exit()
               break
               print "Ende Schleife"
           
        

  
        
    def keysym2String(self, key):
        """
        wandelt die keys in chars um
        z.b. 'Return' wird zu '\n'
        """
        if self.shiftPressed:
            # in grossbuchstaben wandeln!
            key = key.upper()
        if self.altLPressed:
            pass
        if self.altRPressed:
            if key == "2": return "²"
            if key == "3": return "³"
            if key == "7": return "{"
            if key == "8": return "["
            if key == "9": return "]"
            if key == "0": return "}"
            if key == "ß": return "\\"
            if key == "<": return "|"
         
           
        if key == "numbersign": return "#"
        if key == "space": return " "
        if key == "Return": return "\n"
        if key == "Tab": return "\t"
        if key == "period": return "."
        if key == "EQUAL": return "="
        if key == "QUESTION": return "?"
        if key == "PARENLEFT": return "("
        if key == "PARENRIGHT": return ")"
        if key == "EXCLAM": return "!"
        if key == "QUOTEDBL": return "\""
        if key == "SECTION": return "§"
        if key == "DOLLAR": return "$"
        if key == "PERCENT": return "%"
        if key == "AMPERSAND": return "&"
        if key == "SLASH": return "/"
        if key == "ASTERISK": return "*"
        if key == "QUOTERIGHT": return "'"
        if key == "UNDERSCORE": return "_"
        if key == "minus": return "-"
        if key == "plus": return "+"
        if key == "less": return "<"
        if key == "GREATER": return ">"
        if key == "COLON": return ":"
        if key == "comma": return ","
        if key == "SEMICOLON": return ";"
        if key == "Multi_key": return "´"
        if key == "MULTI_KEY": return "`"
     
       
        # ansonsten den ursprünglichen key
        # zurückgeben
        return key

    
    def char2Key(self, char):
        if char == " ": return "leer"
        if char == "\n": return "Return"

        return char


    def openFile(self):
        """
        liest ein File ein und stellt dessen Inhalt
        im outputTxt dar
        """
        print "openFile"
        # Start off with UTF-8
        enc = "utf-8"
        import sys

        """
        # See whether CODESET is defined
        try:
            import locale
            locale.setlocale(locale.LC_ALL,'')
            enc = locale.nl_langinfo(locale.CODESET)
        except (ImportError, AttributeError):
            pass
        """
        
        openfilename=askopenfilename(filetypes=[("all files", "*")])
        try:
           fp=open(openfilename,"r")
           fp.close()
        except:
           print "Could not open File: " 
           print sys.exc_info()[1]

        #print "open", openfilename.encode(enc)

        # Datei einlesen
        #f = open(openfilename.encode(enc))
        f = open(openfilename)
        self.tipper = Tipper(f.read())
        self.outputTxt.insert(1.0, self.tipper.getText())

        # nächsten Buchstaben anzeigen
        char = self.tipper.getNextChar();
        if char == None:
            # ende
            self.reset()
        else:
            self.currLetterLbl["text"] = self.tipper.getNextChar();
        
        

class Tipper:
    def __init__(self, text):
        self.text = text
        self.pos = {"x": 0, "y": 1}
        self.pointer = 0
        
        print self.text

    
    def getPos(self):
        return self.pos
        
    def checkKey(self, key):
              
        print "TEST: "+self.text[self.pointer:self.pointer+1]+" vs. "+ key

        rval = False
        if key == self.text[self.pointer:self.pointer+1]:
            # richtig getippt
            rval = True
       
        if self.text[self.pointer:self.pointer+1] == "\n":
            self.pos["x"] = 0
            self.pos["y"] += 1
        else:              
            self.pos["x"] += 1

        self.pointer += 1

        return rval

    def getNextChar(self):
        return self.text[self.pointer:self.pointer+1]

    def getText(self):
        print "printText"
        sys.stdout.write(self.text)
        return self.text




         

if __name__ == "__main__":
    root = Tk()
    root.title("tos Tipper")
    main = TipperUI(root)
  
    root.mainloop()
    

Verfasst: Samstag 29. Mai 2004, 22:23
von Milan
Hi. Hab das ganze mal nach GUI-Toolkits verschoben, da es mehr in diese Richtung abziehlt. Ich habe aber zu lange nicht mehr intensiv genug mit GUIs gearbeitet, um dir eine prompte Antwort geben zu können (bezüglich dem Ereignis). Da müsste wer anderes ran :) .