Here is my solution: How to easily display a running clock (text, not graphical) using tkinter.
The Clock Class
A running clock requires two functions: One to create the tkinter widget, and one to continuously update the widget with the current time.If we house these in a class, then creating a clock (or multiple clocks) gets much easier. All the complexity is hidden from the mainloop and the rest of your script.
A newly created Clock widget will *automatically* update itself. Both functions call tick(). Yeah, tick() calls itself upon completion. Cool little trick tkinter offers for precisely uses like this.
Here's an example class:
import tkinter import time class Clock(): """ Class that contains the clock widget and clock refresh """ def __init__(self, parent): """ Create the clock widget It's an ordinary Label element """ self.time = time.strftime('%H:%M:%S') self.widget = tkinter.Label(parent, text=self.time) self.widget.after(200, self.tick) # Wait 200 ms, then run tick() def tick(self): """ Update the display clock """ new_time = time.strftime('%H:%M:%S') if new_time != self.time: self.time = new_time self.widget.config(text=self.time) self.widget.after(200, self.tick) # 200 = millisecond delay # before running tick() again
And you implement it rather like this:
if __name__ == "__main__": """ Create a tkinter window and populate it with elements One of those elements merely happens to include the clock. """ # Generic window elements window = tkinter.Tk() frame = tkinter.Frame(window, width=400, height=400 ) frame.pack() # Add the frame elements, including the clock label1 = tkinter.Label(frame, text="Ordinary label") label1.pack() clock2 = Clock(frame) # Create the clock widget clock2.widget.pack() # Add the clock widget to frame label3 = tkinter.Label(frame, text="Ordinary label") label3.pack() window.mainloop()
We created and placed the clock2 widget almost like any other widget. We simply used the Clock class instead of the tkinter.Label class. There's no need to start() or stop() the clock widget - once created, it automatically updates itself.
We can place multiple clock widgets within the same frame without problems.
Advanced Placement
The Clock class works will all geometry managers, just like any widget:clock2.widget.pack() clock2.widget.grid(row=5,column=3) clock2.widget.place(x=150,y=200,anchor=center)
If we don't need to retain the 'clock' variable, or customize it's appearance, then we can simply place it like any other widget:
tkinter.Label(frame, text="Ordinary label").pack() Clock(frame).widget.pack()
Customizing
One easy way to customize the clock's appearance is to use .configureAll Label configure options will work. The clock is simply a label.
clock2 = Clock(frame) # Create the clock widget clock2.widget.pack() # Add the clock widget to frame clock2.widget.configure(bg='green',fg='blue',font=("helvetica",35))
Simplifying
There is one more simplification we can make, detailed as part of this tkinter example. We can change the class to inherit Label properties instead of creating a .widget attribute.If you're new to Python classes, the concept of inheriting from a class may take a few tries to wrap your brain around.
Attribute:
class Clock(): def __init__(self, parent): self.widget = tkinter.Label(parent, text=self.time) if __name__ == "__main__": foo() clock2.widget.do_something() more_foo()
Inherited:
class Clock3(tkinter.Label): def __init__(self, parent=None): tkinter.Label.__init__(self, parent) self.configure(text=self.time) if __name__ == "__main__": foo() clock2.widget.do_something() more_foo()
Final result:
The final clock class looks like:
class Clock3(tkinter.Label): """ Class that contains the clock widget and clock refresh """ def __init__(self, parent=None): tkinter.Label.__init__(self, parent) """ Create and place the clock widget into the parent element It's an ordinary Label element. """ self.time = time.strftime('%H:%M:%S') self.configure(text=self.time, bg='yellow') self.after(200, self.tick) def tick(self): """ Update the display clock every 200 milliseconds """ new_time = time.strftime('%H:%M:%S') if new_time != self.time: self.time = new_time self.config(text=self.time) self.after(200, self.tick)
And you implement it rather like this:
if __name__ == "__main__": """ Create a tkinter window and populate it with elements One of those elements merely happens to include the clock. """ # Generic window elements window = tkinter.Tk() frame = tkinter.Frame(window, width=400, height=400 ) frame.pack() # Add the frame elements, including the clock label1 = tkinter.Label(frame, text="Ordinary label") label1.pack() clock2 = Clock(frame) # Create the clock widget clock2.configure(bg='yellow') # Customize the widget clock2.pack() # Add the clock widget to frame label3 = tkinter.Label(frame, text="Ordinary label") label3.pack() window.mainloop()
No comments:
Post a Comment