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, tkintercanvas=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]+=1write_seconds(remember[1])if remember[1]==60:remember[0]+=1remember[1]=0write_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 Button
s to the top, above the StopWatch
.
from functools import partial
import time
import tkinter as tkPAUSE, 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_timeself.width, self.height = width, heightself.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, Falseself.after_id = Nonedef 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, Falsedef _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 += 1self._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 = Truedef resume_updates(self):if self.paused:self.paused = Falsedef cancel_updates(self):self.running, self.paused = False, Falseif 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: