如何使用tkinter创建计时器?


Answers:


119

Tkinter根窗口具有一种称为的方法after,该方法可用于安排给定时间段后要调用的函数。如果该函数本身调用,则after您已设置了一个自动重复事件。

这是一个工作示例:

# 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()

请记住,after这不能保证该功能将完全按时运行。它仅计划在给定的时间后运行作业。由于Tkinter是单线程的,因此在应用程序忙的情况下,调用它之前可能会有延迟。延迟通常以微秒为单位。


1
递归调用自身不会导致“达到python对象的最大递归”错误吗?
stochastic13

3
@SatwikPasani:不,因为它不是递归调用。它只是将工作放在队列中。
Bryan Oakley

如何仅延迟一次运行func?
user924

1
@ user924 :self.root.after(delay, func)
布莱恩·奥克利

11

使用frame.after()而不是顶级应用程序的Python3时钟示例。还显示了使用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()

1
这是一个很好的答案,有一件重要的事情-显示的时间实际上是系统时间,而不是一些累积的错误时间(如果您等待“大约1000毫秒” 60次,则得到“大约一分钟”而不是60秒,并且错误随着时间而增长)。但是-您的时钟可以跳过显示的秒数-您可以累积亚秒级的错误,然后向前跳过2 s。我建议:self.after(1000 - int(1000 * (time.time() - int(time.time()))) or 1000, self.onUpdate)。最好time.time()在此表达式之前保存到变量。
Tomasz Gandor

2
我渴望变得很棒,可以将xkcd嵌入我的评论中:)
bitsmack

使用frame.after()代替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()

4
如果您可以添加一些说明,将很有帮助。只是复制/粘贴代码很少有用;-)
Martin Tournoij

3
该代码提供了确切的位置时间。它还用作计时器。
Ravikiran D

在我看来,最好使用“%H”代替“%I”,因为“%I”仅显示从0到12的小时数,而不显示时间是AM还是PM。或另一种方式是同时使用“%I”和“%p”(“%p”表示AM / PM)。
Demian Wolf

1

我只是使用MVP模式创建了一个简单的计时器(但是,对于这个简单的项目而言,这可能会显得有些过头)。它具有退出,开始/暂停和停止按钮。时间以HH:MM:SS格式显示。使用每秒运行数次的线程以及计时器启动的时间与当前时间之间的差值来实现计时。

github上的源代码


1

我对这个问题有一个简单的答案。我创建了一个线程来更新时间。我在线程中运行一个while循环,该循环获取时间并对其进行更新。检查以下代码,不要忘记将其标记为正确答案。

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()

这段代码有很多问题。update()函数中的while循环是一个忙循环。从多个线程访问全局变量time_label并不好。
野口健二

但是我觉得,这是最好的方法。因为这不会降低应用程序的性能。
Hardeep Singh,

1

root.after(ms,func)是您需要使用的方法。只需在mainloop启动之前调用它一次,然后在每次调用时在绑定函数中重新计划它。这是一个例子:

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

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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.