如何在 tkinter 中安排更新(更新时钟) ?

我正在用 Python 的 tkinter 库编写一个程序。

我的主要问题是,我不知道如何创建一个 计时器时钟喜欢 hh:mm:ss

我需要它来更新自己(这是我不知道如何做的) ; 当我在一个循环中使用 time.sleep()时,整个 GUI 都冻结了。

141186 次浏览

Tkinter root windows have a method called after which can be used to schedule a function to be called after a given period of time. If that function itself calls after you've set up an automatically recurring event.

Here is a working example:

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

Bear in mind that after doesn't guarantee the function will run exactly on time. It only schedules the job to be run after a given amount of time. It the app is busy there may be a delay before it is called since Tkinter is single-threaded. The delay is typically measured in microseconds.

Python3 clock example using the frame.after() rather than the top level application. Also shows updating the label with a 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()

I just created a simple timer using the MVP pattern (however it may be overkill for that simple project). It has quit, start/pause and a stop button. Time is displayed in HH:MM:SS format. Time counting is implemented using a thread that is running several times a second and the difference between the time the timer has started and the current time.

Source code on github

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

I have a simple answer to this problem. I created a thread to update the time. In the thread i run a while loop which gets the time and update it. Check the below code and do not forget to mark it as right answer.

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

You should call .after_idle(callback) before the mainloop and .after(ms, callback) at the end of the callback function.

Example:

import tkinter as tk
import time




def refresh_clock():
clock_label.config(
text=time.strftime("%H:%M:%S", time.localtime())
)
root.after(1000, refresh_clock)  # <--




root = tk.Tk()


clock_label = tk.Label(root, font="Times 25", justify="center")
clock_label.pack()


root.after_idle(refresh_clock)  # <--
root.mainloop()
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()

You can emulate time.sleep with tksleep and call the function after a given amount of time. This may adds readability to your code, but has its limitations:

def tick():
while True:
clock.configure(text=time.strftime("%H:%M:%S"))
tksleep(0.25) #sleep for 0.25 seconds
    



root = tk.Tk()
clock = tk.Label(root,text='5')
clock.pack(fill=tk.BOTH,expand=True)
tick()
root.mainloop()