7
\$\begingroup\$

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.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jun 22, 2021 at 21:43
\$\endgroup\$
0

1 Answer 1

8
\$\begingroup\$

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()
answered Jun 22, 2021 at 23:35
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Reiderien always displaying his beautiful codes. πŸ‘πŸ»πŸ‘πŸ»πŸ‘πŸ» \$\endgroup\$ Commented 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\$ Commented 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\$ Commented Jun 23, 2021 at 12:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.