Tkinter - How to stop a loop with a stop button? - python

I have this program which beeps every second until it's stopped. The problem is that after I press "Start" and the beeps starts, I cannot click the "Stop" button because the window freezes. Any help is welcome.
#!/usr/bin/python
import Tkinter, tkMessageBox, time, winsound, msvcrt
running = True
Freq = 2500
Dur = 150
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
sec = 0
while running:
if sec % 1 == 0:
winsound.Beep(Freq, Dur)
time.sleep(1)
sec += 1
def stop():
running = False
startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()

There are several things wrong with your code. First of all you shouldn't use time.sleep() in a Tkinter program because it interferes with the mainloop(). Instead one typically uses the universal widget method .after() to schedule a function to run after a specified delay.
Secondly you're not using global variables correctly. When you assign a value to a named variable in a function, it will create a local variable unless that name has been previous declared global. So for instance, your stop() function is creating a local variable named running and setting its value to 0, not changing the value of the global variable with the same name.
The previous rule doesn't apply to just referencing (reading) the current value of a variable. That is why it was OK to not have declared Freq and Dur globals in start().
Another problem is with the sec % 1 == 0 in your start() function. Any value % 1 is 0. To check odd/evenness use sec % 2.
Here's a working version which has also been reformatted to follow PEP 8 - Style Guide for Python Code more closely.
try:
import tkinter as tk
except ModuleNotFoundError:
import Tkinter as tk # Python 2.
import winsound
FREQ = 2500
DUR = 150
after_id = None
secs = 0
def beeper():
global after_id
global secs
secs += 1
if secs % 2 == 0: # Every other second.
winsound.Beep(FREQ, DUR)
after_id = top.after(1000, beeper) # Check again in 1 second.
def start():
global secs
secs = 0
beeper() # Start repeated checking.
def stop():
global after_id
if after_id:
top.after_cancel(after_id)
after_id = None
if __name__ == '__main__':
top = tk.Tk()
top.title('MapAwareness')
top.geometry('200x100')
startButton = tk.Button(top, height=2, width=20, text="Start", command=start)
stopButton = tk.Button(top, height=2, width=20, text="Stop", command=stop)
startButton.pack()
stopButton.pack()
top.mainloop()
Update
Since this answer has become fairly popular, I'd like touch on another slightly more advanced topic — namely how making the code more object-oriented would simplify things by eliminating the need almost all of the global variables.
try:
import tkinter as tk
except ModuleNotFoundError:
import Tkinter as tk # Python 2.
import winsound
FREQ = 2500
DUR = 150
class Application(tk.Frame, object):
def __init__(self, master=None):
super(Application, self).__init__(master) # Call base class initializer.
self.after_id = None
self.secs = 0
# Create widgets,
startButton = tk.Button(top, height=2, width=20, text="Start", command=self.start)
stopButton = tk.Button(top, height=2, width=20, text="Stop", command=self.stop)
startButton.pack()
stopButton.pack()
def beeper(self):
self.secs += 1
if self.secs % 2 == 0: # Every other second.
winsound.Beep(FREQ, DUR)
self.after_id = top.after(1000, self.beeper) # Check again in 1 second.
def start(self):
self.secs = 0
self.beeper() # Start repeated checking.
def stop(self):
if self.after_id:
top.after_cancel(self.after_id)
self.after_id = None
if __name__ == '__main__':
top = tk.Tk()
app = Application()
app.master.title('MapAwareness')
app.master.geometry('200x100')
app.mainloop()

You code have top.mainloop() which has a while loop running inside it and on top of that you also have a while loop inside def start():. So it is like loop inside loop.
You can create a function that does what you want for the body of the loop. It should do exactly one iteration of the loop. Once it is done, it needs to arrange for itself to be called again some time in the future using after. How far in the future defines how fast your loop runs.
And you can then use after_cancel to cancel the event. Below code worked for me
import Tkinter, tkMessageBox, time, winsound, msvcrt
Freq = 2500
Dur = 150
top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
global job1
if running == True:
winsound.Beep(Freq, Dur)
job1 = top.after(1000, start) # reschedule event in 1 seconds
def stop():
global job1
top.after_cancel(job1)
startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
#top.after(1000, start)
top.mainloop()

The problem is that the while loop in start() blocks the GUI handler mainloop(). Try using Tk.after() in start():
def start(force=True):
global running
if force:
running = True
if running:
winsound.Beep(Freq, Dur)
top.after(1000, start, False)
And change stop():
def stop():
global running
running = False

Beaten to the punch again but here goes nothing. As above use the after function to prevent the mainloop blocking.
See:
tkinter: how to use after method
#!/usr/bin/python
import Tkinter, tkMessageBox, time
Freq = 2500
Dur = 150
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
print ("Beep")
top.after(1000, start)
def stop():
print ("Stop")
top.quit()
startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()

I used thread and global variable to fit your need. Not so complicated if you understand how they work. Just an addition of few lines and minor change to your existing line, and it works. Look through to see the changes made to your original code.
#!/usr/bin/python
import tkinter
from tkinter import messagebox
import time, winsound, msvcrt
from threading import Thread
running = True
Freq = 2500
Dur = 150
top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def button_click():
global running #create global
running = True
# Create new thread
t = Thread(target = start)
# Start new thread
t.start()
def start():
sec = 0
while running:
if running == False:
break
if sec % 1 == 0:
winsound.Beep(Freq, Dur)
time.sleep(1)
sec += 1
def stop():
global running #create global
running = False
startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = button_click) #Change to call button_click instead start
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
top.mainloop()

from threading import Thread
def stttart():
t1=Thread(target=start)
t1.start()
def start():
...
def stop():
...
startButton = Tkinter.Button(top, height=2, width=20, text ="Start", command = stttart)
stopButton = Tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
https://www.geeksforgeeks.org/how-to-use-thread-in-tkinter-python/
last year, this had been my big problem for some months

Related

How to break a while loop with a tkinter button without freezeing the executable

I've tried by now several methods found online but I can't seem to find a solution.
What I want to create is to enable a while loop with a button and disable it with another button.
The main issue, is that while the loop is active, it freezes my GUI when I press my "disable" button. The while loop does stop, but I have to kill the executable in task manager and restart it in order to re-enable the while loop.
Code:
from tkinter import *
import time
top = Tk()
top.title("Corsair")
top.geometry('100x100')
top.resizable(False, False)
def b1():
while True:
[MY MAIN CODE]
# if But2.is_pressed:
# break
but1 = Button(top, image = onbutton, text ="On", command = b1)
but2 = Button(top, image = offbutton, text ="Off", pady = 100, padx = 10, command = top.destroy)
but1.pack()
but2.pack()
top.mainloop()
I've tried;
if But2.is_pressed to break the code, which freezes the GUI.
Make but2 to destroy top window, which freezes the GUI.
I've tried ;
x = 1
def b1():
while True:
if x == 1:
[MY MAIN CODE]
else:
break
def b2():
x = 0
but1 = Button(top, image = onbutton, text ="On", command = b1)
but2 = Button(top, image = offbutton, text ="Off", pady = 100, padx = 10, command = b2)
but3 = Button(top, text ="Exit", pady = 100, padx = 20, command = top.destroy)
This problem was few times on Stackoverflow:
If you run long-running loop then you should run it in separate thread.
But if every loop is not so long then you could use .after(milliseconds, function_name) at the end of function (instead of while and sleep) to repeat function again - and this will work as loop, and tkinter will have time to run own mainloop
import tkinter as tk # PEP8: `import *` is not preferred
import time
# --- functions --- # PEP8: all functions before main code
def b1():
print('MY MAIN CODE')
if running:
# repeat after 100ms (0.1s)
top.after(100, b1) # funcion's name without ()
else:
print('STOP')
def b2():
global running
running = False
# --- main ---
running = True
top = tk.Tk()
but1 = tk.Button(top, text="On", command=b1) # PEP8: inside `()` use `=` without spaces
but2 = tk.Button(top, text="Off", command=b2)
but1.pack()
but2.pack()
top.mainloop()
EDIT:
If you want to use button On to restart loop again then it may need extra function to set again running = True
import tkinter as tk # PEP8: `import *` is not preferred
import time
# --- functions --- # PEP8: all functions before main code
def b1():
global running
running = True
loop()
def loop():
print('MY MAIN CODE')
if running:
# repeat after 100ms (0.1s)
top.after(100, loop) # funcion's name without ()
else:
print('STOP')
def b2():
global running
running = False
# --- main ---
running = True
top = tk.Tk()
but1 = tk.Button(top, text="On", command=b1) # PEP8: inside `()` use `=` without spaces
but2 = tk.Button(top, text="Off", command=b2)
but1.pack()
but2.pack()
top.mainloop()

while loop/thread problem with stopwatch program

So I am making a stopwatch program with tkinter.
At the moment, I am in the process of implementing a stop button for the stopwatch.
I can start the stopwatch and it will update the Label fine but my end button isn't working and I can't seem to figure out why.
Here's my code so far:
from tkinter import *
from time import sleep
import threading
root = Tk()
root.title("Clock")
class Buttons:
def __init__(self, master):
self.menu = Menu(master)
master.config(menu=self.menu)
self.menu.add_command(label="Stopwatch")
self.menu.add_command(label="Timer")
self.menu.add_command(label="Quit", command=quit)
self.stopwatchStart = Button(master, text="Start", command=self.test_start)
self.stopwatchStart.config(height=2, width=5)
self.stopwatchStart.grid(row=0)
self.stopwatchEnd = Button(master, text="End", command=self.stopwatch_End)
self.stopwatchEnd.config(height=2, width=5)
self.stopwatchEnd.grid(row=1)
self.labelSeconds = Label(master, text="Seconds:")
self.labelSeconds.grid(row=0, column=1)
self.stopwatchSeconds = Label(master, text="0")
self.stopwatchSeconds.grid(row=0, column=2)
def test_start(self):
print("Starting thread")
t = threading.Thread(target=self.stopwatch_Start)
t.setDaemon(True)
t.start()
def stopwatch_Start(self, test=False):
print("Stopwatch started")
stopwatch_seconds = "0"
stopwatchBreak = test
print(f"stopwatchBreak == {stopwatchBreak}")
while not stopwatchBreak:
print(stopwatch_seconds)
stopwatch_seconds = int(stopwatch_seconds)
stopwatch_seconds += 1
self.stopwatchSeconds.config(text=stopwatch_seconds)
root.update()
sleep(1)
print("Stopping stopwatch")
return
def stopwatch_End(self):
Buttons.stopwatch_Start(self, True)
print("Attempting to end")
b = Buttons(root)
root.mainloop()
I am using threading to run the stop watch and the window from tkinter at the same time by the way.
Also I have put several print() across the functions to see what is succeeding and what isn't. I think the problem may have something to do with the thread in test_start(). The loop that won't end when I click the end button is in stopwatch_Start(). It just keeps counting up.
I have received no error messages
Does anyone have any suggestions/alternatives to stopping the stopwatch?
look at this code
def stopwatch_End(self):
Buttons.stopwatch_Start(self, True)
print("Attempting to end")
this is your problem =>
Buttons.stopwatch_Start(self, True)
correct this with:
self.stopwatch_Start(True)
here you are call "stopwatch" on the class Buttons, this is an unbound function!!!
"Buttons.stopwatch" is different than "self.stopwatch" the later is bound to the instance.
from tkinter import *
from time import sleep
from threading import Thread
from threading import Event
root = Tk()
root.title("Clock")
class Buttons:
def __init__(self, master):
self.evt = Event()
self.menu = Menu(master)
master.config(menu=self.menu)
self.menu.add_command(label="Stopwatch")
self.menu.add_command(label="Timer")
self.menu.add_command(label="Quit", command=quit)
self.stopwatchStart = Button(master, text="Start", command=self.test_start)
self.stopwatchStart.config(height=2, width=5)
self.stopwatchStart.grid(row=0)
self.stopwatchEnd = Button(master, text="End", command=self.stopwatch_End)
self.stopwatchEnd.config(height=2, width=5)
self.stopwatchEnd.grid(row=1)
self.labelSeconds = Label(master, text="Seconds:")
self.labelSeconds.grid(row=0, column=1)
self.stopwatchSeconds = Label(master, text="0")
self.stopwatchSeconds.grid(row=0, column=2)
def test_start(self):
print("Starting thread")
t = Thread(target=self.stopwatch_Start)
t.setDaemon(True)
t.start()
def stopwatch_Start(self, test=False):
print("Stopwatch started")
stopwatch_seconds = "0"
stopwatchBreak = test
print(f"stopwatchBreak == {stopwatchBreak}")
# self.evt.is_set() will force the loop to check its actually state if it True or not
while not self.evt.is_set():
print(stopwatch_seconds)
stopwatch_seconds = int(stopwatch_seconds)
stopwatch_seconds += 1
self.stopwatchSeconds.config(text=stopwatch_seconds)
root.update()
sleep(1)
print("Stopping stopwatch")
return
def stopwatch_End(self):
#we set self.evt to True so that the while loop will be broken
self.evt.set()
print("Attempting to end")
b = Buttons(root)
root.mainloop()

While Loop In Tkinter with Pyautogui

I'm trying to create a mouse loop application, I can get the start button to work inside the loop, however the end button seems to crash tkinter instead of close the application.
any advise would be appreciated
import pyautogui
from tkinter import *
import sys
window = Tk()
def start_loop():
while True:
pyautogui.moveTo(3131, 891, 1)
pyautogui.PAUSE = 180
pyautogui.moveTo(3128, 434, 1)
b1 = Button(window, text="Start Mouse", command=start_loop)
b1.grid(row=0, column=0)
def end_loop():
print(sys.exit())
b2 = Button(window, text="Stop Mouse", command=end_loop)
b2.grid(row=0, column=1)
window.mainloop()
This can also be achieved using threading.
It will consume more resources, but I think it would be less "clunky" as a end result.
I added comments about the timing and some print statements to track what is happening:
import pyautogui
from tkinter import *
import threading
import sys
import time
window = Tk()
t = False
def start_thread():
"""Starts the Mouse thread"""
global t
if t:
return
t = threading.Thread(target = start_loop)
setattr(t, "flag", False)
t.start()
print("Mouse thread Started")
def start_loop():
"""Loop that moves the mouse"""
t = threading.current_thread()
time.sleep(0.1) # Just for better printing
while True:
print("Mouse thread Running")
pyautogui.moveTo(3131, 891, 1)
# Not sure you wanted to adjust the pyautogui time to 180, or just wait 180 seconds.
#pyautogui.PAUSE = 180
for x in range(180):
time.sleep(1)
flag = getattr(t, "flag")
if flag:
print("Mouse thread Stopped")
return
pyautogui.moveTo(3128, 434, 1)
def end_loop():
"""Ends the mouse loop"""
global t
if not t:
return
setattr(t, "flag", True)
while t.is_alive():
time.sleep(0.1)
t = False
b1 = Button(window, text="Start Mouse", command=start_thread)
b1.grid(row=0, column=0)
b2 = Button(window, text="Stop Mouse", command=end_loop)
b2.grid(row=0, column=1)
window.mainloop()
You should use after function.
In tkinter, it should check each component of interfaces with loop (I mean mainloop).
However, if you use while True:, then the GUI cannot check the reactions about the other functions or interfaces like Button.
So, your program can be downed.
import pyautogui
from tkinter import *
import sys
window = Tk()
def start_loop():
pyautogui.moveTo(3131, 891, 1)
pyautogui.PAUSE = 1.8
pyautogui.moveTo(3128, 434, 1)
window.after(180, start_loop) //after(ms_for_delay, function)
b1 = Button(window, text="Start Mouse", command=start_loop)
b1.grid(row=0, column=0)
def end_loop():
sys.exit()
b2 = Button(window, text="Stop Mouse", command=end_loop)
b2.grid(row=0, column=1)
window.mainloop()
Try this code.

How to stop a program with infinity loop in Python (tkinter)?

I have a problem with stopping the program. When I click exit button, the mainloop stops but program is still running. I am new to it and I have no idea what to do. I know the issue is the thread is still running and I don't know how to stop it.
This is my code:
from tkinter import *
import simulation as s
import graph as g
import numpy as np
from tkinter import filedialog
import threading
def main():
root = Tk()
root.title("Simulator")
switch = True
def get_filename():
return filedialog.askopenfilename(parent=root)
def play():
def run():
while switch:
s.simulation(s.particle, np.inf, s.initial_time_step, get_filename())
thread = threading.Thread(target=run)
thread.start()
def start_simulation():
global switch
switch = True
v.set('Simulation is running!')
play()
def stop_simulation():
global switch
v.set('Simulation is stopped!')
switch = False
def draw_graphs():
g.create_graphs()
start = Button(root, text='Start simulation', command=start_simulation, width=50)
start.pack()
finish = Button(root, text='Stop simulation', command=stop_simulation, width=50)
finish.pack()
graphs = Button(root, text='Graphs', command=draw_graphs, width=50)
graphs.pack()
exit_button = Button(root, text='Exit', command=root.destroy, width=50)
exit_button.pack()
v = StringVar()
statement = Label(root, textvariable=v)
statement.pack()
root.mainloop()
if __name__ == '__main__':
main()
Create a function for the exit button which also stops your thread
def exit():
switch = False
root.destroy()
And later:
exit_button = Button(root, text='Exit', command=exit, width=50)
You can also call the same method whenever the window is closed with the top right X button. Just bind your method to the event:
root.protocol("WM_DELETE_WINDOW", exit)
Ps: You dont need to use global here, because your nested functions have access to the outer functions variables

Label Is Not Shown When Called From Other Tkinter Program

I was writing a program with a start page, and two programs that are called from that start page. Both of the subprograms work by themselves. However, when I put them into my start page, the stopwatch timing label doesn't show up. If you are wondering, I put them into my program by doing:
import program
program.function()
Here is my start page program:
from Tkinter import *
class start_page:
def __init__(self,master):
self.master = master
self.frame = Frame(self.master)
self.countdown = Button(master, text = "Timer", command = self.c).pack()
self.stopwatch_butt = Button(master,text="Stopwatch",command=self.g).pack()
def g(self):
import stopwatch
stopwatch.f()
def c(self):
import timer_prog
timer_prog.timer()
self.master.after_cancel(timer_prog)
def main():
root = Tk()
s = start_page(root)
root.title("Timer Suite: Brian Ton")
root.mainloop()
main()
If I run this program, the timer program works fine, but the stopwatch doesn't show its label, only its buttons. I tried to clear all Tk after functions, and that didn't work, and I also tried to run the stopwatch program first, to no avail.
Here is my stopwatch program:
from Tkinter import *
import datetime
def s():
start.config(state='disabled')
stop.config(state="normal")
reset.config(state='disabled')
Start()
def Start():
if reset['state'] == 'disabled' and stop['state'] == 'normal':
hidden.set(str(int(hidden.get())+1))
root.update()
root.after(1000,Start)
curr = hidden.get()
g.set(str(datetime.timedelta(seconds=int(curr))))
print g.get()
else:
return None
def Stop():
start.config(state='disabled')
stop.config(state='disabled')
reset.config(state="normal")
def Reset():
start.config(state="normal")
stop.config(state="disabled")
reset.config(state='disabled')
hidden.set('0')
g.set(str(datetime.timedelta(seconds=0)))
def f():
global root,frame,master,hidden,g,timelabel,start,stop,reset
root = Tk()
frame = Frame(root)
master = root
hidden = StringVar()
g = StringVar()
hidden.set('0')
timelabel = Label(master,textvariable=g)
g.set(str(datetime.timedelta(seconds=int(0))))
timelabel.grid(row=1,column=2)
start = Button(master,text="Start",command = s,state="normal")
stop = Button(master,text="Stop",command = Stop,state = "disabled")
reset = Button(master,text="Reset",command = Reset,state = "disabled")
start.grid(row=2,column=1)
stop.grid(row=2,column=2)
reset.grid(row=2,column=3)
root.update()
root.mainloop()
And here is my timer program:
from Tkinter import *
import datetime
def get_seconds(h,m,s):
hr_sec = h * 3600
m_sec = m * 60
return hr_sec+m_sec+s
def timerstartstop():
hours = hour_entry.get()
minutes = minute_entry.get()
sec = second_entry.get()
if hours == "":
hours = 0
hour_entry.insert(0,"0")
if minutes == "":
minutes = 0
minute_entry.insert(0,"0")
if sec == "":
sec = 0
second_entry.insert(0,"0")
c = get_seconds(int(hours), int(minutes), int(sec))
global s
s = StringVar(master)
s.set(c)
if startstop['text'] == 'Stop':
global curr
curr = shown
s.set(-1)
if startstop['text'] == 'Reset':
startstop.config(text="Start")
s.set(c)
root.update()
shown.set(str(datetime.timedelta(seconds=int(s.get()))))
return None
countdown()
import winsound
def countdown():
startstop.config(text="Stop")
global shown
good = True
shown = StringVar(master)
shown.set(str(datetime.timedelta(seconds=int(s.get()))))
L = Label(master,textvariable=shown).grid(row=1,column=2)
if int(s.get()) == 0:
startstop.config(text="Reset")
while startstop['text'] != "Start":
root.update()
winsound.Beep(500,500)
elif int(s.get()) < 0:
good = False
shown.set(curr.get())
startstop.config(text="Reset")
else:
if good:
s.set(str(int(s.get())-1))
root.after(1000,countdown)
def ex():
root.after_cancel(countdown)
root.destroy()
def timer():
global root
global master
global frame
root = Tk()
master = root
frame = Frame(master)
global hour_entry
hour_entry = Entry(master,width=3)
hour_entry.grid(row=0,column=0)
colon_l = Label(master,text=':').grid(row=0,column=1)
global minute_entry
minute_entry = Entry(master,width=2)
minute_entry.grid(row=0,column=2)
colon_l2 = Label(master,text=':').grid(row=0,column=3)
global second_entry
second_entry = Entry(master,width=2)
second_entry.grid(row=0,column=4)
global startstop
startstop = Button(master,text="Start",command=timerstartstop)
e = Button(master,text="Exit",command=ex).grid(row=1,column=3)
startstop.grid(row=0,column=5)
root.mainloop()
In addition, I tried to run these two programs from a different starting menu that used the console, which worked.
The console program is:
import timer_prog
timer_prog.timer()
raw_input('next')
import stopwatch
stopwatch.f()
Attached are some screenshots of what the stopwatch program should look like vs what it does look like when called from the starting program.
Note: I can tell the program is running from the starting page, as it prints the current time each second. Also, I attached some screenshots
Stopwatch Program Run Directly
Stopwatch Program Run From The Start Page
Tkinter program should use only one Tk() - to create main window - and one mainloop() - to control all windows and widgets. If you use two Tk() and two mainloop() then it has problem - for example get()/set() may not work.
Subwindows should use Toplevel() instead of Tk().
Function which starts program (ie. run()) could run with parameter window (def run(window)) and then you can execute it as standalone program with
root = Tk()
run(root)
root.mainloop()
or after importing
run(Toplevel())
(without maniloop())
You can use if __name__ == "__main__" to recognize if program starts as standalone.
Example
main.py
from Tkinter import *
class StartPage:
def __init__(self, master):
self.master = master
master.title("Timer Suite: Brian Ton")
Button(master, text="Timer", command=self.run_timer).pack()
Button(master, text="Stopwatch", command=self.run_stopwatch).pack()
def run_stopwatch(self):
import stopwatch
window = Toplevel()
stopwatch.run(window)
def run_timer(self):
import timer_prog
window = Toplevel()
timer_prog.timer(window)
self.master.after_cancel(timer_prog)
def main():
root = Tk()
StartPage(root)
root.mainloop()
main()
stopwatch.py
from Tkinter import *
import datetime
def pre_start():
start_button.config(state='disabled')
stop_button.config(state='normal')
reset_button.config(state='disabled')
start()
def start():
global current_time
# stop_button['state'] can be 'normal' or 'active' so better use ` != 'disabled'`
if reset_button['state'] == 'disabled' and stop_button['state'] != 'disabled':
current_time += 1
time_var.set(str(datetime.timedelta(seconds=current_time)))
print(time_var.get())
master.after(1000, start)
def stop():
start_button.config(state='disabled')
stop_button.config(state='disabled')
reset_button.config(state='normal')
def reset():
global current_time
start_button.config(state='normal')
stop_button.config(state='disabled')
reset_button.config(state='disabled')
current_time = 0
time_var.set(str(datetime.timedelta(seconds=0)))
def run(window):
global master
global current_time, time_var
global start_button, stop_button, reset_button
master = window
current_time = 0
time_var = StringVar()
time_var.set(str(datetime.timedelta(seconds=0)))
time_label = Label(window, textvariable=time_var)
time_label.grid(row=1, column=2)
start_button = Button(master, text='Start', command=pre_start, state='normal')
stop_button = Button(master, text='Stop', command=stop, state='disabled')
reset_button = Button(master, text='Reset', command=reset, state='disabled')
start_button.grid(row=2, column=1)
stop_button.grid(row=2, column=2)
reset_button.grid(row=2, column=3)
if __name__ == '__main__':
# it runs only in standalone program
root = Tk()
run(root)
root.mainloop()

Categories