I have a countdown script where seconds updates quickly as I press start and pause button few times one after another.
At first I thought clicking quickly between start and pause buttons speeds the seconds so I added time.sleep(1)
to delay click between the buttons which didn't worked.
How can I fix this problem?
Is my algorithm correct? Or Is there other better way to make the countdown time? If yes, how can I do it?
CODE
from tkinter import *
PAUSE = False
HOUR, MINUTE, SECOND = 0, 0, 0
def start():
'''Command for START button'''
global PAUSE
PAUSE = False
start_button['state'] = 'disabled'
pause_button['state'] = 'normal'
reset_button['state'] = 'normal'
# time.sleep(1) to delay time between clicks of pause and start buttons
Counter()
def pause():
'''Command for PAUSE button'''
global PAUSE
PAUSE = True
start_button['state'] = 'normal'
pause_button['state'] = 'disabled'
def reset():
'''Command for RESET button'''
global HOUR, MINUTE, SECOND, PAUSE
PAUSE = True
start_button['state'] = 'normal'
pause_button['state'] = 'disabled'
reset_button['state'] = 'disabled'
Time['text'] = '00:00:00'
HOUR, MINUTE, SECOND = 0, 0, 0
def Counter():
'''Updating hour, minute and seconds'''
global HOUR, MINUTE, SECOND
if PAUSE is False:
if SECOND == 59:
if MINUTE == SECOND == 59:
HOUR += 1
if MINUTE == 59:
MINUTE = 0
else:
MINUTE += 1
SECOND = -1
SECOND += 1
Time.config(text='{}:{}:{}'.format(str(HOUR).zfill(2), str(MINUTE).zfill(2), str(SECOND).zfill(2)))
root.after(1000, Counter)
root = Tk()
root.title('COUNTER')
width, height = 342, 108
pos_x = root.winfo_screenwidth() // 2 - width // 2
pos_y = root.winfo_screenheight() // 2 - height // 2
root.geometry('{}x{}+{}+{}'.format(width, height, pos_x, pos_y))
Time = Label(root, fg='Black', text='00:00:00', font=("Helvetica", 40))
Time.pack(side='bottom')
start_button = Button(root, text='START', font=("Arial", 16), fg='black', width=8, command=start)
start_button.pack(side='left')
pause_button = Button(root, text='PAUSE', font=("Arial", 16), fg='black', width=8, state='disabled', command=pause)
pause_button.pack(side='left')
reset_button = Button(root, text='RESET', font=("Arial", 16), fg='black', width=10, state='disabled', command=reset)
reset_button.pack(side='left', fill='both')
root.mainloop()
Your Counter
function calls root.after(1000,Counter)
each click and also modify the Time
label instant upon clicking. When you click the buttons quick enough, you can schedule multiple root.after
and also add up the seconds.
To modify your current script, you can keep track on the current action, and call root.after_cancel
to pause the action.
from tkinter import *
PAUSE = False
HOUR, MINUTE, SECOND = 0, 0, 0
action = None #keep track on current action and also avoid click spam
def start():
'''Command for START button'''
global PAUSE, action
PAUSE = False
...
if not action:
Counter()
def pause():
'''Command for PAUSE button'''
global PAUSE, action
...
if action:
root.after_cancel(action)
action = None
def reset():
'''Command for RESET button'''
global HOUR, MINUTE, SECOND, PAUSE, action
...
HOUR, MINUTE, SECOND = 0, 0, 0
action = None
def Counter():
'''Updating hour, minute and seconds'''
global HOUR, MINUTE, SECOND, action
if PAUSE is False:
if SECOND == 59:
if MINUTE == SECOND == 59:
HOUR += 1
if MINUTE == 59:
MINUTE = 0
else:
MINUTE += 1
SECOND = -1
SECOND += 1
Time.config(text='{}:{}:{}'.format(str(HOUR).zfill(2), str(MINUTE).zfill(2), str(SECOND).zfill(2)))
action = root.after(1000, Counter)
root = Tk()
...
start_button = Button(root, text='START', font=("Arial", 16), fg='black', width=8, command=lambda: root.after(1000,start)) #to avoid the instant second increment
At first I thought clicking quickly between start and pause buttons speeds the seconds so I added time.sleep(1) to delay click between the buttons which didn't worked.
The problem is that because there is a delay before the .aftert()
method calls back on itself, hit the start Button multiple times and create multiple loops of the .after(1000, counter)
. meaning there are many .after()
loops happening at once. To fix this you just need to make it so then the start button cannot be pressed if there is a .after()
loop going on.
To do this you must change three of your functions
The
counter()
function
I have changed the code so then if the counter is running, then the start_button
will be disabled, and when the counter stops running its state will be back to normal
def Counter():
'''Updating hour, minute and seconds'''
global HOUR, MINUTE, SECOND
if PAUSE is False:
start_button['state'] = 'disabled' # setting it to disabled if the counter is running
if SECOND == 59:
if MINUTE == SECOND == 59:
HOUR += 1
if MINUTE == 59:
MINUTE = 0
else:
MINUTE += 1
SECOND = -1
SECOND += 1
Time.config(text='{}:{}:{}'.format(str(HOUR).zfill(2), str(MINUTE).zfill(2), str(SECOND).zfill(2)))
root.after(1000, Counter)
else:
start_button['state'] = 'normal' # setting it to normal if the counter stops
The
pause()
andreset()
functions
You must remove the ability to set the state of the start_button
to normal, because this will allow the start_button
to be pressed before the last counter loop finished
def pause():
'''Command for PAUSE button'''
global PAUSE
PAUSE = True
pause_button['state'] = 'disabled'
def reset():
'''Command for RESET button'''
global HOUR, MINUTE, SECOND, PAUSE
PAUSE = True
pause_button['state'] = 'disabled'
reset_button['state'] = 'disabled'
Time['text'] = '00:00:00'
HOUR, MINUTE, SECOND = 0, 0, 0
Updating these functions will remove this bug. Hope this is the answer you were looking for :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.