How to break out of an infinite loop with a Tkinter button? How to break out of an infinite loop with a Tkinter button? tkinter tkinter

How to break out of an infinite loop with a Tkinter button?


Python doesn't exactly support interrupts, the closest thing would probably be some sort of signal handler, which are supported via its signal library. However they may not work well with Tkinter (or pygame), so I don't think that would be a good approach—and they're not really necessary anyway because what you want to do can be handled within Tkinter's mainloop().

Although it may seem somewhat complex, the way I would suggest implementing it would be to encapsulate most of the playing control functionality within a single Python class. This will reduce the use of global variables, which will make the program easier to debug and develop further (because of the many advantages of Object-Oriented Programming — aka as OOP).

Below illustrates what I mean. Note, I'm using Python 3, so had to make a few additional changes to your code in order for it would work with that version. I'm not sure, but this version ought to work in Python 2, as well, except you'll need to change the import of the Tkinter module as indicated.

from pygame import *from tkinter import *  # Change to "from Tkinter import *" for Python 2.x.class PlayController(object):    def __init__(self, mixer, music_filename, polling_delay):        self.mixer = mixer        self.music_filename = music_filename        self.polling_delay = polling_delay  # In milliseconds.        self.playing = False    def play(self):        if self.playing:            self.stop()        self.mixer.music.load(self.music_filename)        self.mixer.music.play(-1)  # -1 means to loop indefinitely.        self.playing = True        root.after(self.polling_delay, self.check_status)  # Start playing check.    def stop(self):        if self.playing:            self.mixer.music.stop()            self.playing = False    def check_status(self):        if self.playing:            print('playing')        root.after(self.polling_delay, self.check_status)  # Repeat after delay.root = Tk()root.geometry("1000x200")root.title("Sampler")mixer.init()play_control = PlayController(mixer, 'tone.wav', 1000)Button(root, text="Play", command=play_control.play).pack()Button(root, text="Stop", command=play_control.stop).pack()mainloop()


You need to add a command to your button... stop = Button(root, text="Stop", command=stop)


Just adding a stop command probably wont work because the way your infinite loop is structured, you can't interact with the tkinter interface while play is clicked. Try restructuring your program like this:

from Tkinter import *from pygame import *import timeimport threadingswitch = Trueroot = Tk()n = 1mixer.init()root.geometry("1000x200")root.title("sampler")def play():    def run():        while switch:            print 'playing'            mixer.music.load('audio 1.mp3')            mixer.music.play()            time.sleep(n)            if not switch:                break    thread = threading.Thread(target=run)    thread.start()def switch_on():    global switch    switch = True    play()def switch_off():    global switch    switch = Falsedef kill():    root.destroy()onbutton = Button(root, text="Play", command=switch_on)onbutton.pack()offbutton = Button(root, text="Stop", command=switch_off)offbutton.pack()killbutton = Button(root, text="Kill", command=kill)killbutton.pack()root.mainloop()

This way the tkinter buttons are running on separate threads, so while one is looping you can still interact with the other.