TKinter - How to stop a loop with a stop button?
<p>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.</p>

<pre><code>#!/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()
</code></pre>

<p>There are several things wrong with your code. First of all you shouldn't use <code>time.sleep()</code> in a Tkinter program because it interferes with the <code>mainloop()</code>. Instead one typically uses the universal widget method <a href="http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/universal.html" rel="nofollow"><code>.after()</code></a> to schedule a function to run after a specified delay.</p>

<p>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 <code>global</code>. So for instance, your <code>stop()</code> function is creating a local variable named <code>running</code> and setting its value to 0,  <em>not</em> changing the value of the global variable with the same name.</p>

<p>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 <code>Freq</code> and <code>Dur</code> globals in <code>start()</code>.</p>

<p>Another problem is with the <code>sec % 1 == 0</code> in your <code>start()</code> function. Any value <code>% 1</code> is <code>0</code>. To check odd/evenness use <code>sec % 2</code>.</p>

<p>Here's a working version which has also been reformatted to follow <a href="https://www.python.org/dev/peps/pep-0008/" rel="nofollow">PEP 8 - Style Guide for Python Code</a> more closely.</p>

<pre><code>import Tkinter
import tkMessageBox
import time
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

top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100')

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()
</code></pre>

python tkinter