stop the clock within the time limit in tkinter python - python

I want to stop clock within the time limit, here i have given 5 seconds but the clock is not stopping, kindly help.
import tkinter as tk
from tkinter.constants import *
def start():
global hours, minutes, seconds
if hours == 4:
return
seconds -= 1
if seconds == 00:
minutes -= 1
seconds = 60
if minutes == 00 and seconds == 00:
hours = hours+1
clock.config(text=f'{hours:02}:{minutes:02}:{seconds:02}')
root.after(1000, start)
root=tk.Tk()
clock = tk.Label(root, font=("bold",20), anchor=CENTER, text="00:00:00")
clock.place(relx=0.5, rely=0.5, anchor=CENTER)
hours,minutes,seconds = 0,0,5
start()
root.mainloop()

Just add the variable stop and if stop == True then the clock will stop
Solution to your Question
import tkinter as tk
from tkinter.constants import *
def start():
global hours, minutes, seconds, stop
if hours == 4:
return
if stop == False:
seconds -= 1
if seconds == 00:
stop = True
elif seconds == 00 and minutes != 00 and hours != 00:
minutes -= 1
seconds = 60
elif minutes == 00 and seconds == 00:
hours = hours+1
clock.config(text=f'{hours:02}:{minutes:02}:{seconds:02}')
root.after(1000, start)
root=tk.Tk()
clock = tk.Label(root, font=("bold",20), anchor=CENTER, text="00:00:00")
clock.place(relx=0.5, rely=0.5, anchor=CENTER)
hours,minutes,seconds,stop = 0,0,5, False
start()
root.mainloop()
a Complete clock down counter BONUS
import tkinter as tk
from tkinter.constants import *
def start():
global hours, minutes, seconds, stop
if hours == 4:
return
if stop == False:
seconds -= 1
if seconds == 00 and minutes == 00 and hours == 00:
stop = True
elif seconds == -1 and minutes != 00:
minutes -= 1
seconds = 59
elif hours != 00 and minutes == 00 and seconds == -1:
hours -= 1
minutes = 59
seconds = 59
clock.config(text=f'{hours:02}:{minutes:02}:{seconds:02}')
root.after(1000, start)
root=tk.Tk()
clock = tk.Label(root, font=("bold",20), anchor=CENTER, text="00:00:00")
clock.place(relx=0.5, rely=0.5, anchor=CENTER)
hours,minutes,seconds,stop = 0,0,5, False
start()
root.mainloop()

Solution without that many if conditions. I use a timestamp, but I have also some trouble with the timezone I think. Maybe someone can solve my offsets.
My tkinter TIMER app, with bell:
import tkinter as tk
import calendar
from datetime import datetime
import time
import sys
class Countdown(tk.Frame):
def __init__(self,master):
tk.Frame.__init__(self, master)
global target
self.master = master
self.clock = tk.Label(text="00:00:00", fg="Green", font=("bold",40))
self.clock.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
timestamp = calendar.timegm(time.localtime())
print("Timestamp",timestamp)
print("Timestamp_future",timestamp + t_plus)
target = timestamp + t_plus
self.update_clock()
def update_clock(self):
current = calendar.timegm(time.localtime()) -23*3600
countdown = target - current
self.down_time = datetime.fromtimestamp(countdown).strftime("%H:%M:%S")
self.clock.configure(text=self.down_time)
if countdown/3600 != 23:
self.after(1000, self.update_clock)
else:
print('\a', end='', flush=True)
root = tk.Tk()
global t_plus
######### SET YOUR TIME FOR THE COUNTDOWN ############
your_timer_set = '00:00:05' # hours, minutes, seconds
######################################################
countdown = time.strptime(your_timer_set, '%H:%M:%S')
hours = int(countdown.tm_hour)
minutes = int(countdown.tm_min)
seconds = int(countdown.tm_sec)
t_plus = ((hours*3600)+(minutes*60)+seconds)
print("SET_TIME",t_plus)
app=Countdown(root)
root.title("Countdown")
root.geometry("400x400+400+150")
root.mainloop()

Related

How can I use a single button to pause and unpause timer in tkinter? (without using pygame)

I'm working on a simple timer that counts down 30 mins for me to study and 5 mins for a break. So far, the start_timer function and count_down function work well, I just cannot figure out how to write the pause function. I did some research for a few days. Most articles are using pygame or to bind with different keys. I am wondering what function I should use for one tkinter button to pause/unpause my timer if something comes up and I want to pause the timer till I'm back.
Thank you #TimRoberts, I can pause the timer now. However, I don't know how to unpause the timer to let it continue counting down.
from tkinter import *
import math
WORK_MIN = 30
BREAK_MIN = 5
reps = 0
paused = False
# --------------------------- TIMER ---------------------------- #
def start_timer():
global reps
reps += 1
work_sec = WORK_MIN * 60
break_sec = BREAK_MIN * 60
if reps % 2 == 1:
title_label.config(text="Study")
count_down(work_sec)
else:
title_label.config(text="Break")
count_down(break_sec)
window.attributes('-topmost', 0)
# ------------------------ COUNTDOWN--------------------------- #
def count_down(count):
global paused
count_min = math.floor(count / 60)
count_sec = count % 60
if count_min < 10:
count_min = f"0{count_min}"
if count_sec < 10:
count_sec = f"0{count_sec}"
canvas.itemconfig(timer_text, text=f"{count_min}:{count_sec}" )
if count > 0:
if not paused:
count -= 1
window.after(1000, count_down, count-1)
else:
start_timer()
# ---------------------------- PAUSE ------------------------------- #
def pause_function():
global paused
paused = not paused
# ---------------------------- UI ------------------------------- #
window = Tk()
title_label = Label(text="Timer")
title_label.grid(column=1, row=0)
check_marks = Label(text="")
check_marks.grid(column=1, row=4)
canvas = Canvas(width=200, height=224, bg="lightblue")
timer_text = canvas.create_text(100, 128, text="00:00", fill="white", font=("Courier", 45, "bold"))
canvas.grid(column=1, row=1)
start_button = Button(text="Start", command=start_timer)
start_button.grid(column=0, row=2)
pause_button = Button(text="Pause", command=pause_function)
pause_button.grid(column=2, row=2)
window.mainloop()
You need to do the "after" call even if you're paused, otherwise you'll never notice when you unpause. Also, since you're decrementing count once, you don't need to do it again:
def count_down(count):
count_min = count // 60
count_sec = count % 60
canvas.itemconfig(timer_text, text=f"{count_min:02d}:{count_sec:02d}" )
if count:
if not paused:
count -= 1
window.after(1000, count_down, count)
else:
start_timer()
If you want to be tricky, you could use:
if count:
count -= not paused
since True is 1 and False is 0.

Tkinter How to fix After issue caused by Recursion

WORK_MIN = 12
SHORT_BREAK_MIN = 5
LONG_BREAK_MIN = 20
reps = 0
def start_timer():
global reps
work_min = WORK_MIN * 60
long_break = LONG_BREAK_MIN * 60
short_break = SHORT_BREAK_MIN * 60
while True:
reps += 1
if reps % 8 == 0:
countdown(long_break)
elif reps % 2 == 1:
countdown(work_min)
else:
countdown(short_break)
def countdown(second_count):
minute_time = int(second_count / 60)
# minute_time = math.floor(second_count / 60)
if len(str(minute_time)) == 1:
minute_time = f"0{minute_time}"
second_time = second_count % 60
if len(str(second_time)) == 1:
second_time = f"0{second_time}"
if second_count > 0:
window.after(1000, countdown, second_count - 1)
window = Tk()
window.title("Pomodoro Practice")
window.config(padx=100, pady=50, bg=YELLOW)
window.minsize(width=300, height=300)
start_timer()
window.mainloop()
Whenever I run this code, it skips over window.after(1000, countdown, second_count - 1) and returns back to the while loop in start_timer(). I would like the countdown function to be called recursively after waiting for a second until second count == 0.
Add break to the end of all your while conditions, and add an else condition to the end of countdown that restarts start_timer.
WORK_MIN = 12
SHORT_BREAK_MIN = 5
LONG_BREAK_MIN = 20
reps = 0
def start_timer():
global reps
work_min = WORK_MIN * 60
long_break = LONG_BREAK_MIN * 60
short_break = SHORT_BREAK_MIN * 60
while True:
reps += 1
if reps % 8 == 0:
countdown(long_break)
break
elif reps % 2 == 1:
countdown(work_min)
break
else:
countdown(short_break)
break
def countdown(second_count):
minute_time = int(second_count / 60)
# minute_time = math.floor(second_count / 60)
if len(str(minute_time)) == 1:
minute_time = f"0{minute_time}"
second_time = second_count % 60
if len(str(second_time)) == 1:
second_time = f"0{second_time}"
canvas.itemconfig(timer_text, text=f"{minute_time}:{second_time}")
if second_count > 0:
window.after(1000, countdown, second_count - 1)
else:
start_timer()
start_timer()
You can also just get rid of the while loop entirely, but still add the condition to the end of countdown. However, if you are going to "trim the fat", trim it all. It's interesting that you work for 12 minutes, break for 5 (3 times) and then you work for 12 and break for 20. So, in 83 minutes you work 48 and break for 35. Sounds like a helluva job. If you worked for me you could have a float('inf') minute break ... cause you'd be fired. :D
import tkinter as tk
window = tk.Tk()
canvas = tk.Canvas(window, width=800, height=600)
canvas.pack()
timer_text = canvas.create_text(50, 50, font='Helvetica 24 bold')
reps = 0
def start_timer():
global reps
reps += 1
if reps % 8 == 0:
countdown(20*60)
elif reps % 2 == 1:
countdown(12*60)
else:
countdown(5*60)
def countdown(seconds):
canvas.itemconfig(timer_text, text=f"{seconds//60:02}:{seconds%60:02}")
window.after(1000, countdown, seconds-1) if seconds else start_timer()
start_timer()
if __name__ == '__main__':
window.mainloop()

Tkinter lag at the "update" command

I made a timer just to test something out. and for some reason it starts lagging, here is the timer:
from tkinter import *
from time import sleep
main = Tk()
main.title("Timer")
c = Canvas(main,width=1000,height=400)
c.pack()
c.config(bg="black")
hours = -1
while True:
hours += 1
for minutes in range(60):
for seconds in range(60):
c.create_rectangle(0,0,1000,400,fill="black")
c.create_text(500,200,text=(str(hours)+":"+str(minutes)+":"+str(seconds)),font=("",200),fill="white")
c.update()
sleep(1)
Can someone figure out where it happens? I noticed I can run the timer without tkinter and just with print, but I need to use tkinter for other projects too.
You are creating text widgets covered by black rectangles in succession, without ever removing them - in essence, every second, you are piling two more canvas items on top of all the previous ones!
The correct approach is to use the tkinter.mainloop in conjunction with the tkinter.after method, and steer clear from using a while loop, and tkinter.update. You can change the text displayed by a canvas text item using itemconfigure.
The use of time.sleep in a GUI is a recipe to have your GUI stop responding to interactions - don't do that!
Maybe do this instead:
import tkinter as tk
def update_clock():
clock_text = f'{hours}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}'
canvas.itemconfigure(clock, text=clock_text)
main.after(1000, _increment_time)
def _increment_time():
global clock, hours, minutes, seconds
seconds += 1
if seconds == 60:
seconds = 0
minutes += 1
if minutes == 60:
minutes = 0
hours += 1
update_clock()
main = tk.Tk()
main.title('Timer')
canvas = tk.Canvas(main, width=1000, height=400, bg='black')
canvas.pack()
hours, minutes, seconds = 0, 0, 0
clock = canvas.create_text(500, 200, font=('', 200), fill='white')
update_clock()
main.mainloop()

time function always gives me 0.0 output

Im trying to make a CPS counter, and when I reach 100 clicks, its supposed to print "test" and also print the time it took to get to 100 clicks. But it always gives 0.0 as the time output.
import tkinter
import time
counter = tkinter.Tk()
clicks = 0
def addClick():
global clicks
clicks = clicks + 1
lbl.configure(text=clicks)
start = time.time()
if clicks == 100:
print("test")
end = time.time()
print(start - end)
lbl = tkinter.Label(counter, text = clicks)
lbl.pack()
btn = tkinter.Button(counter, text="Click here", command=addClick)
btn.pack()
counter.mainloop()
...
start = time.time()
if clicks == 100:
print("test")
end = time.time()
print(start - end)
You keep restarting start after every click. A possible solution would be to start it only after the first click. This will require start to be a global variable as well.
Also note that you should do end - start, not start - end.
clicks = 0
start = None
...
global clicks
global start
...
if clicks == 1:
# instantiating 'start' only if it was the first click
start = time.time()
elif clicks == 100:
print("test")
end = time.time()
print(end - start)
However, using global variables is quite a code-smell and an anti-pattern, and we already have 2 of them in such a tiny program.
You can try to wrap them in a data-structure such as a dict:
import tkinter
import time
counter = tkinter.Tk()
data = {'clicks': 0, 'start': None}
def addClick():
data['clicks'] += 1
lbl.configure(text=data['clicks'])
if data['clicks'] == 1:
# instantiating 'start' only if it was the first click
data['start'] = time.time()
elif data['clicks'] == 100:
print("test")
end = time.time()
print(end - data['start'])
lbl = tkinter.Label(counter, text=data['clicks'])
lbl.pack()
btn = tkinter.Button(counter, text="Click here", command=addClick)
btn.pack()
counter.mainloop()
Another, real-world fitting solution would be to wrap the entire tkinter app in a class, that can keep track of its own state.

how to stop timer at 20 minutes

I am making a timer that starts when the user hits "space" and stops on "p", showing the ending time. I can I stop it at a maximum time of 20 minutes? Is there something like
if time_passed==20:
break
My code:
from turtle import*
from datetime import datetime
...
def start():
undo()
global break1, timerint, startime
break1 = 0
startime = datetime.now()
while True:
timerint = datetime.now()-startime
write(timerint,font=("Arial",50))
undo()
if break1 == 1:
break
def stop():
global break1, timerint, startime
timerint=datetime.now()-startime
write(timerint,font=("Arial",50))
break1 = 1
# Turtle placement code removed
onkeypress(start,"space")
onkeypress(stop,"p")
listen()
No, but you can always check elapsed time with the time.time() method.
import time
start = time.time()
while ...
....
now = time.time()
if now - start > 20 * 60:
break
That's the low-tech version. If you want more sophisticated things, such as a separate timer process, try a full browser search for "Python timer process".
Also, you might consider using Boolean values:
global timer_running, timerint, startime
timer_running = True
startime = datetime.now()
while timer_running:
timerint = datetime.now()-startime
write(timerint,font=("Arial",50))
undo()
def stop():
global timer_running, timerint, startime
timerint = datetime.now()-startime
write(timerint, font=("Arial", 50))
timer_running = False
I recommend getting rid of the while loop and instead build upon turtle's ontimer() events:
from turtle import Turtle, Screen
from datetime import datetime
FONT = ("Arial", 50)
def start():
global timer_running, start_time
if timer_running:
return
start_time = datetime.now()
timer_running = True
screen.ontimer(lambda time=start_time: automatic_stop(time), 20 * 60 * 1000)
screen.ontimer(update, 100)
def update():
if not timer_running:
return
timerint = datetime.now() - start_time
marker.undo()
marker.write(timerint, align='center', font=FONT)
screen.ontimer(update, 100)
def manual_stop():
global timer_running
if not timer_running:
return
timer_running = False
timerint = datetime.now() - start_time
marker.undo()
marker.write(timerint, align='center', font=FONT)
def automatic_stop(time):
global timer_running
if timer_running and start_time == time: # make sure *this* timer is still valid
timer_running = False
marker.undo()
marker.write("Expired!", align='center', font=FONT)
screen = Screen()
marker = Turtle(visible=False)
marker.penup()
marker.write("Hit 'space' to start timer; 'p' to stop", align='center', font=FONT)
start_time = None
timer_running = False
screen.onkeypress(start, "space")
screen.onkeypress(manual_stop, "p")
screen.listen()
screen.mainloop()
We pass automatic_stop() a copy of start_time so that when it wakes up in the distant future it can check if it is still a valid end event or not based on the current start_time. (If you work at the Tk level instead of turtle, you might be able to cancel the timer when no longer needed.)

Categories