While learning about python tkinter, I decided to make a digital clock:
from datetime import datetime
import tkinter as tk
from threading import Thread
import time
class clock():
def __init__(self):
self.display = tk.Tk()
def start(self):
def get():
self.display.geometry("215x62")
self.display.title("Clock")
while True:
try:
now = datetime.now()
current_time = now.strftime("%H:%M %p")
lbl = tk.Label(self.display, text=str(current_time),
background = 'black', font = ("Helvetica", 37),
foreground = 'red')
lbl.place(x=0, y=0)
time.sleep(0.1)
except:
break
receive_thread = Thread(target=get)
receive_thread.start()
self.display.mainloop()
clock = clock()
clock.start()
Is there any way to make this clock better?
Any comments, answers, or steps in the right direction would be appreciated.
1 Answer 1
To start, it's crucial that you stop creating a brand new label ten times a second. Just modify the existing one. Also, this is so simple that a class is not called for. Move as much as possible away from your thread, into your setup routine. Finally, your use of %H
is likely incorrect given that you also include %p
; you probably want %I
for a 12-hour clock.
This all suggests:
from datetime import datetime
import tkinter as tk
from threading import Thread
from time import sleep
def main():
display = tk.Tk()
display.geometry('215x62')
display.title('Clock')
lbl = tk.Label(
display,
background='black',
font=('Helvetica', 37),
foreground='red',
)
lbl.place(x=0, y=0)
def get():
while True:
now = datetime.now()
lbl.config(text=now.strftime('%I:%M %p'))
sleep(0.1)
receive_thread = Thread(target=get)
receive_thread.start()
display.mainloop()
if __name__ == '__main__':
main()
Ten times a second is overkill, and you can safely make this much sleepier. Do not make a thread at all; use an after()
timer, and calculate when exactly the clock should tick:
from datetime import datetime
import tkinter as tk
from time import time
def main() -> None:
display = tk.Tk()
display.geometry('215x62')
display.title('Clock')
lbl = tk.Label(
display,
background='black',
font=('Helvetica', 37),
foreground='red',
)
lbl.place(x=0, y=0)
def tick() -> None:
now = datetime.now()
lbl.config(text=now.strftime('%I:%M %p'))
until_next = round(
1000 * (60 - time()%60)
)
display.after(ms=until_next, func=tick)
tick()
display.mainloop()
if __name__ == '__main__':
main()
-
1\$\begingroup\$ Reiderien always displaying his beautiful codes. ππ»ππ»ππ» \$\endgroup\$ARNON– ARNON2021εΉ΄06ζ23ζ₯ 02:35:34 +00:00Commented Jun 23, 2021 at 2:35
-
\$\begingroup\$ Won't your second code run into stack size limitations after 1000 seconds, since each invocation of
tick
starts a new one? \$\endgroup\$Graipher– Graipher2021εΉ΄06ζ23ζ₯ 08:56:56 +00:00Commented Jun 23, 2021 at 8:56 -
1\$\begingroup\$ @Graphier I don't think so.
after
is asynchronous. It's not going to recurse - this is telling tk to use the event loop and schedule a callback for a later time. \$\endgroup\$Reinderien– Reinderien2021εΉ΄06ζ23ζ₯ 12:28:17 +00:00Commented Jun 23, 2021 at 12:28