Wie erstelle ich einen Timer mit tkinter?

Antworten:

122

Tkinter-Stammfenster verfügen über eine Methode, mit afterder eine Funktion geplant werden kann, die nach einem bestimmten Zeitraum aufgerufen werden soll. Wenn diese Funktion selbst aufgerufen wird, haben afterSie ein automatisch wiederkehrendes Ereignis eingerichtet.

Hier ist ein Arbeitsbeispiel:

# for python 3.x use 'tkinter' rather than 'Tkinter'
import Tkinter as tk
import time

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.label = tk.Label(text="")
        self.label.pack()
        self.update_clock()
        self.root.mainloop()

    def update_clock(self):
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.root.after(1000, self.update_clock)

app=App()

Beachten Sie, dass afterdies nicht garantiert, dass die Funktion genau pünktlich ausgeführt wird. Es wird nur geplant, dass der Job nach einer bestimmten Zeit ausgeführt wird. Wenn die App ausgelastet ist, kann es zu einer Verzögerung kommen, bevor sie aufgerufen wird, da Tkinter Single-Threaded ist. Die Verzögerung wird typischerweise in Mikrosekunden gemessen.

Bryan Oakley
quelle
1
Verursachen die rekursiven Aufrufe an sich selbst nicht den Fehler "Maximale Rekursionen für ein Python-Objekt erreicht"?
stochastisch13
3
@ SatwikPasani: Nein, weil es kein rekursiver Aufruf ist. Es stellt lediglich einen Job in eine Warteschlange.
Bryan Oakley
Wie kann man func nur einmal mit Verzögerung ausführen?
user924
1
@ user924 : self.root.after(delay, func).
Bryan Oakley
12

Beispiel für eine Python3-Uhr mit der Datei frame.after () anstelle der Anwendung der obersten Ebene. Zeigt auch die Aktualisierung des Labels mit einem StringVar ()

#!/usr/bin/env python3

# Display UTC.
# started with https://docs.python.org/3.4/library/tkinter.html#module-tkinter

import tkinter as tk
import time

def current_iso8601():
    """Get current date and time in ISO8601"""
    # https://en.wikipedia.org/wiki/ISO_8601
    # https://xkcd.com/1179/
    return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        self.now = tk.StringVar()
        self.time = tk.Label(self, font=('Helvetica', 24))
        self.time.pack(side="top")
        self.time["textvariable"] = self.now

        self.QUIT = tk.Button(self, text="QUIT", fg="red",
                                            command=root.destroy)
        self.QUIT.pack(side="bottom")

        # initial time display
        self.onUpdate()

    def onUpdate(self):
        # update displayed time
        self.now.set(current_iso8601())
        # schedule timer to call myself after 1 second
        self.after(1000, self.onUpdate)

root = tk.Tk()
app = Application(master=root)
root.mainloop()
David Poole
quelle
1
Dies ist eine gute Antwort, mit einer wichtigen Sache: Die angezeigte Zeit ist wirklich die Systemzeit und nicht eine akkumulierte Fehlerzeit (wenn Sie 60 Mal "ungefähr 1000 ms" warten, erhalten Sie "ungefähr eine Minute", nicht 60 Senconds, und der Fehler wächst mit der Zeit). Wenn Ihre Uhr jedoch Sekunden auf dem Display überspringen kann, können Sie Fehler in Sekundenschnelle akkumulieren und dann z. B. 2 Sekunden vorwärts überspringen. Ich würde vorschlagen : self.after(1000 - int(1000 * (time.time() - int(time.time()))) or 1000, self.onUpdate). Wahrscheinlich ist es besser, time.time()vor diesem Ausdruck in einer Variablen zu speichern .
Tomasz Gandor
3
Ich strebe danach, großartig genug zu sein, um xkcd's in meine Kommentare einzubetten :)
bitsmack
Was ist der Vorteil der Verwendung von frame.after () anstelle von root.after ()?
Kai Wang
6
from tkinter import *
import time
tk=Tk()
def clock():
    t=time.strftime('%I:%M:%S',time.localtime())
    if t!='':
        label1.config(text=t,font='times 25')
    tk.after(100,clock)
label1=Label(tk,justify='center')
label1.pack()
clock()
tk.mainloop()
Ravikiran D.
quelle
4
Es wäre hilfreich, wenn Sie eine Beschreibung hinzufügen könnten. Nur Code kopieren / einfügen ist selten nützlich ;-)
Martin Tournoij
3
Dieser Code gibt die genaue Zeit des Ortes an. Er dient auch als Timer.
Ravikiran D
Es scheint mir, es wäre besser, "% H" anstelle von "% I" zu verwenden, da "% I" nur die Stunden von 0 bis 12 anzeigt und nicht anzeigt, ob die Zeit AM oder PM ist. Oder Sie verwenden auch "% I" und "% p" ("% p" gibt AM / PM an).
Demian Wolf
1

Ich habe gerade einen einfachen Timer mit dem MVP-Muster erstellt (es kann jedoch für dieses einfache Projekt übertrieben sein). Es hat Quit, Start / Pause und eine Stop-Taste. Die Zeit wird im Format HH: MM: SS angezeigt. Die Zeitzählung wird mithilfe eines Threads implementiert, der mehrmals pro Sekunde ausgeführt wird, und der Differenz zwischen der Zeit, zu der der Timer gestartet wurde, und der aktuellen Zeit.

Quellcode auf Github


quelle
1

Ich habe eine einfache Antwort auf dieses Problem. Ich habe einen Thread erstellt, um die Zeit zu aktualisieren. Im Thread führe ich eine while-Schleife aus, die die Zeit abruft und aktualisiert. Überprüfen Sie den folgenden Code und vergessen Sie nicht, ihn als richtige Antwort zu markieren.

from tkinter import *
from tkinter import *
import _thread
import time


def update():
    while True:
      t=time.strftime('%I:%M:%S',time.localtime())
      time_label['text'] = t



win = Tk()
win.geometry('200x200')

time_label = Label(win, text='0:0:0', font=('',15))
time_label.pack()


_thread.start_new_thread(update,())

win.mainloop()
Hardeep Singh
quelle
Dieser Code weist eine Vielzahl von Problemen auf. Die while-Schleife in der update () -Funktion ist eine Besetztschleife. Der Zugriff auf die globale Variable time_label von mehreren Threads aus ist nicht besonders gut.
Kenji Noguchi
Aber ich denke, das ist der beste Weg, es zu tun. weil dies die Leistung der Anwendung nicht verringert.
Hardeep Singh
1

Die root.after (ms, func) ist die Methode, die Sie verwenden müssen. Rufen Sie es einfach einmal auf, bevor der Mainloop startet, und planen Sie es bei jedem Aufruf innerhalb der gebundenen Funktion neu. Hier ist ein Beispiel:

from tkinter import *
import time


def update_clock():
    timer_label.config(text=time.strftime('%H:%M:%S',time.localtime()),
                  font='Times 25')  # change the text of the time_label according to the current time
    root.after(100, update_clock)  # reschedule update_clock function to update time_label every 100 ms

root = Tk()  # create the root window
timer_label = Label(root, justify='center')  # create the label for timer
timer_label.pack()  # show the timer_label using pack geometry manager
root.after(0, update_clock)  # schedule update_clock function first call
root.mainloop()  # start the root window mainloop
Demian Wolf
quelle
0
from tkinter import *

from tkinter import messagebox

root = Tk()

root.geometry("400x400")

root.resizable(0, 0)

root.title("Timer")

seconds = 21

def timer():

    global seconds
    if seconds > 0:
        seconds = seconds - 1
        mins = seconds // 60
        m = str(mins)

        if mins < 10:
            m = '0' + str(mins)
        se = seconds - (mins * 60)
        s = str(se)

        if se < 10:
            s = '0' + str(se)
        time.set(m + ':' + s)
        timer_display.config(textvariable=time)
        # call this function again in 1,000 milliseconds
        root.after(1000, timer)

    elif seconds == 0:
        messagebox.showinfo('Message', 'Time is completed')
        root.quit()


frames = Frame(root, width=500, height=500)

frames.pack()

time = StringVar()

timer_display = Label(root, font=('Trebuchet MS', 30, 'bold'))

timer_display.place(x=145, y=100)

timer()  # start the timer

root.mainloop()
Meruemu
quelle