Tkinter timer to start at 0 on button click - python

I would like to create a timer that starts at 0 when a user presses a button and stop at whatever time it has displayed when the user presses the button again. So far, all of the questions user after that looks at the current time and updates in seconds from whatever time it is like so:
def timer(self):
now = time.strftime("%H:%M:%S")
self.label.configure(text=now)
self.after(1000, self.timer)
But I would like to start at zero, display the minutes and seconds. Is there anyway to achieve this?

Here's a simple stopwatch GUI. There's some room for improvement. ;)
import tkinter as tk
from time import time
class Stopwatch:
def __init__(self):
root = tk.Tk()
root.title('Stopwatch')
self.display = tk.Label(root, text='00:00', width=20)
self.display.pack()
self.button = tk.Button(root, text='Start', command=self.toggle)
self.button.pack()
self.paused = True
root.mainloop()
def toggle(self):
if self.paused:
self.paused = False
self.button.config(text='Stop')
self.oldtime = time()
self.run_timer()
else:
self.paused = True
self.oldtime = time()
self.button.config(text='Start')
def run_timer(self):
if self.paused:
return
delta = int(time() - self.oldtime)
timestr = '{:02}:{:02}'.format(*divmod(delta, 60))
self.display.config(text=timestr)
self.display.after(1000, self.run_timer)
Stopwatch()
The toggle method toggles the stopwatch on or off. The run_timer method updates the display Label with the time since the timer started, in minutes & seconds. For more accuracy, reduce the .after delay to say, 500, or 100. That will do unnecessary (and invisible) updates to the Label, but the displayed time will be a little more accurate, and the GUI will feel a little more responsive.

import tkinter as tk
import time
class GUI:
def __init__(self, master):
self.root = master
self.parent = tk.Frame(self.root)
self.parent.pack(fill = tk.BOTH)
self.parent.config(bg = "black")
self.now = time.time()
self.buttonVar = tk.IntVar()
self.buttonCycle = False
self.buttonVar.set(0)
self.button = tk.Button(root,
textvariable = self.buttonVar,
command = self.updateButton)
self.button.pack(fill = tk.BOTH)
self.button_cycle()
def updateButton(self):
if self.buttonCycle:
self.buttonCycle = False
self.now = time.time()
elif not self.buttonCycle:
self.buttonCycle = True
def button_cycle(self):
if self.buttonCycle:
now = time.time()
timeDifference = int(now - self.now)
self.buttonVar.set(timeDifference)
self.root.after(1000, self.button_cycle)
root = tk.Tk()
myApp = GUI(root)
root.mainloop()

Related

How to create a timer with tkinter? I am learning Python [duplicate]

I'm writing a program with Python's tkinter library.
My major problem is that I don't know how to create a timer or a clock like hh:mm:ss.
I need it to update itself (that's what I don't know how to do); when I use time.sleep() in a loop the whole GUI freezes.
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()
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()
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()
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()
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 *
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()

Pause and continue stopwatch

I am trying to create stopwatch. I have done it but I would like to pause and continue the time whenever I want. I have tried some things but I have no idea how to do it. Is there anybody who would explain me how to do it?
import time, tkinter
canvas=tkinter.Canvas(width=1900,height=1000,bg='white')
canvas.pack()
canvas.create_text(950,300,text=':',font='Arial 600')
def write(x_rec,y_rec,x_text,rep):
canvas.create_rectangle(x_rec,0,y_rec,750,outline='white',fill='white')
if rep<10:
canvas.create_text(x_text,400,text='0'+str(rep),font='Arial 600')
else:
canvas.create_text(x_text,400,text=str(rep),font='Arial 600')
def write_minutes(rep):
write(0,900,450,rep)
def write_seconds(rep):
write(1000,1900,1450,rep)
def time(num,remember):
while remember[0]<num:
remember[1]+=1
write_seconds(remember[1])
if remember[1]==60:
remember[0]+=1
remember[1]=0
write_seconds(remember[1])
write_minutes(remember[0])
canvas.update()
canvas.after(1000)
remember=[0,0]
num=1
write_seconds(remember[1])
write_minutes(remember[0])
time(5,remember)
I couldn't figure-out a clean way to modify your code to do what you want, so decided to implement the stop watch as a class to make the program more object-oriented and avoid the use of a bunch of global variables.
I haven't tested this thoroughly, but there's enough of it working to give you the idea. Note also that I changed a Resume button into one that toggles itself between that and being Pause button. This approach made adding a third one unnecessary.
Update
I noticed what could be potential problem because more and more objects keep getting added to the Canvas as the display is updated. This shouldn't be a problem for a short-running StopWatch instance, but might cause issues with a long-running one.
To avoid this, I modified the code to update the existing corresponding Canvas text object if there is one. I also moved the Buttons to the top, above the StopWatch.
from functools import partial
import time
import tkinter as tk
PAUSE, RESUME = 0, 1 # Button states.
# Button callback functions.
def _toggle(callback):
toggle_btn.state = 1 - toggle_btn.state # Toggle button state value.
toggle_btn.config(**toggle_btn_states[toggle_btn.state])
callback()
def _stop():
stopwatch.cancel_updates()
toggle_btn.config(state=tk.DISABLED)
stop_btn.config(state=tk.DISABLED)
class StopWatch:
def __init__(self, parent, run_time, width, height):
self.run_time = run_time
self.width, self.height = width, height
self.font = 'Arial 600'
self.canvas = tk.Canvas(parent, width=width, height=height, bg='white')
self.canvas.pack()
self.canvas.create_text(950, 300, text=':', font=self.font)
self.running, self.paused = False, False
self.after_id = None
def start(self):
self.elapsed_time = 0 # In seconds.
self._display_time()
self.after_id = self.canvas.after(1000, self._update)
self.running, self.paused = True, False
def _update(self):
if self.running and not self.paused:
if self.elapsed_time == self.run_time:
_stop() # Sets self.running to False.
self.canvas.bell() # Beep.
else:
self.elapsed_time += 1
self._display_time()
if self.running: # Keep update process going.
self.after_id = self.canvas.after(1000, self._update)
def _display_time(self):
mins, secs = divmod(self.elapsed_time, 60)
self._write_seconds(secs)
self._write_minutes(mins)
def _write_minutes(self, mins):
self._write(0, 900, 450, 'mins', mins)
def _write_seconds(self, secs):
self._write(1000, 1900, 1450, 'secs', secs)
def _write(self, x_rec, y_rec, x_text, tag, value):
text = '%02d' % value
# Update canvas text widget if it has non-empty text.
if self.canvas.itemcget(tag, 'text'):
self.canvas.itemconfigure(tag, text=text)
else: # Otherwise create it.
self.canvas.create_text(x_text, 400, text=text, tag=tag, font=self.font)
def pause_updates(self):
if self.running:
self.paused = True
def resume_updates(self):
if self.paused:
self.paused = False
def cancel_updates(self):
self.running, self.paused = False, False
if self.after_id:
self.canvas.after_cancel(self.after_id)
self.after_id = None
# main
root = tk.Tk()
# Create a Frame for Buttons (allows row of them to be centered).
button_frame = tk.Frame(root)
button_frame.pack(side=tk.TOP)
# Create StopWatch and configure buttons to use it.
stopwatch = StopWatch(root, 5, 1900, 1000)
toggle_btn = tk.Button(button_frame)
toggle_btn_states = {}
# Dictionary mapping state to button configuration.
toggle_btn_states.update({
PAUSE: dict(
text='Pause', bg='red', fg='white',
command=partial(_toggle, stopwatch.pause_updates)),
RESUME: dict(
text='Resume', bg='green', fg='white',
command=partial(_toggle, stopwatch.resume_updates))
})
toggle_btn.state = PAUSE
toggle_btn.config(**toggle_btn_states[toggle_btn.state])
toggle_btn.pack(side=tk.LEFT, padx=2)
stop_btn = tk.Button(button_frame, text='Stop', bg='blue', fg='white', command=_stop)
stop_btn.pack(side=tk.LEFT, padx=2)
stopwatch.start()
root.mainloop()
Here's a screenshot showing the stopwatch running:

How to make timer/program open only after pressing key instead of immediately?

I need to make this clock open only after pressing a key, lets say "t". Now it opens immediately after running it.
import tkinter as tk
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state=True
state = False
root = tk.Tk()
root.wm_title('Simple Kitchen Timer Example')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
update_timeText()
root.mainloop()
It is in another program so as I have my graphics window I will press "t" and the clock will open.
Keyboard is a python module that can detect keystrokes. Install it by doing this command.
pip install keyboard
Now you can do this.
while True:
try:
if keyboard.is_pressed('t'):
state = True
elif(state != True):
pass
except:
state = False
break #a key other than t the loop will break
I would recommend you to organize the code little bit, like class structure. One possible implementation would be like that:
import tkinter as tk
TIMER = [0, 0, 0]
PATTERN = '{0:02d}:{1:02d}:{2:02d}'
class Timer:
def __init__(self, master):
#I init some variables
self.master = master
self.state = False
self.startButton = tk.Button(root, text='Start', command=lambda: self.start())
self.startButton.pack()
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
def start(self):
self.state = True
self.update_timeText()
def update_timeText(self):
if (self.state):
global TIMER
TIMER[2] += 1
if (TIMER[2] >= 100):
TIMER[2] = 0
TIMER[1] += 1
if (TIMER[1] >= 60):
TIMER[0] += 1
TIMER[1] = 0
timeString = PATTERN.format(TIMER[0], TIMER[1], TIMER[2])
self.timeText.configure(text=timeString)
self.master.after(10, self.update_timeText)
if __name__ == '__main__':
root = tk.Tk()
root.geometry("900x600")
root.title("Simple Kitchen Timer Example")
graph_class_object = Timer(master=root)
root.mainloop()
So clock will start when you click to button. If you want to start the clock by pressing "t" in keyboard, you need to bind that key to your function.
You can also add functionality if you want to stop the clock when you click to the button one more time.
EDIT:
if you also want to start to display the clock by clicking the button, you can move the code for initializing the label in to start function.
def start(self):
self.state = True
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
self.update_timeText()

How do I properly update the countdown timer in one second intervals in the main window? [duplicate]

I'm writing a program with Python's tkinter library.
My major problem is that I don't know how to create a timer or a clock like hh:mm:ss.
I need it to update itself (that's what I don't know how to do); when I use time.sleep() in a loop the whole GUI freezes.
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()
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()
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()
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()
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 *
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()

Make a reminder which will remind every X minute using Tkinter

I am totally new in python GUI and Tkinter. Now i want an entry field where i can change the value or time of self.hide when i will execute this code. that means self.hide value will change from Entry field. In this code this value is statically set to 1 minute. need help from experts.
import Tkinter as Tk
import time
import tkMessageBox
class Window:
def __init__(self):
self.root = None
self.hide = 1 #minutes
self.show = 3 #seconds
def close(self):
self.root.destroy()
return
def new(self):
self.root = Tk.Tk()
self.root.overrideredirect(True)
self.root.geometry("{0}x{1}+0+0".format(self.root.winfo_screenwidth(), self.root.winfo_screenheight()))
self.root.configure(bg='black')
Tk.Label(self.root, text='Hello', fg='white', bg='black', font=('Helvetica', 30)).place(anchor='center', relx=0.5, rely=0.5)
#tkMessageBox.showinfo("Notification", "Your time is up. Time to do next job. . .")
Tk.Button(text = 'Close', command = self.close).pack()
self.root.after(self.show*1000, self.pp)
def pp(self):
if self.root:
self.root.destroy()
time.sleep(self.hide*60)
self.new()
self.root.mainloop()
return
Window().pp()
Try This. It may help you.
from Tkinter import *
import time
root = Tk()
def close():
root.destroy()
def show():
root.deiconify()
button.config(text = 'Close', command = close)
root.after(1000, hide)
def hide():
root.withdraw()
time_to_sleep = set_time_to_sleep.get()
time_to_sleep = float(time_to_sleep)
#print time_to_sleep
time.sleep(time_to_sleep)
show()
set_time_to_sleep = Entry(root)
set_time_to_sleep.pack(side=LEFT)
button = Button(text = 'Set Time', command = hide)
button.pack()
root.mainloop()
To summarise:
Instead of using the sleep function, use the after function. This will not freeze the GUI.
Set the "wait" time of the after function self.Entry.get(). This will collect the info you have put into the Entry.
For more info, look at these links. People smarter than myself give a very clear explication on how to use the functions.
Tkinter, executing functions over time
tkinter: how to use after method

Categories

Resources