Search code examples
pythonclassuser-interfacetkinterwhile-loop

starting/stopping while loops with button in tkinter


By using two different buttons, I'm trying to start and stop a process based on a while loop that scans through patterns (actually just counting in this example). In the following code, I have tried to simplify and generalise the more complex process that occurs in the actual project I'm working on. As you can see by running the code, you can start the count by pressing the play button; when you press the stop button though, the process doesn't stop immediately. I have previously managed to make it work as desired, but while rewriting the code with an object oriented approach, nothing is working properly anymore. At the moment, I can't understand anymore if the problem is in the while loop construction or if I'm working with threads in the wrong way. Any suggestion is very welcome and appreciated!

from tkinter import *
import threading
import time

class gui:

    def __init__(self, window):

        #play button
        self.play_frame = Frame (master = window, relief = FLAT, borderwidth = 1)
        self.play_frame.grid (row = 0, column = 0, padx = 1, pady = 1)
        self.play_button = Button (self.play_frame, text = "play", fg = "blue", command = lambda: self.play(1))
        self.play_button.pack()
        #stop button
        self.stop_frame = Frame (master = window, relief = FLAT, borderwidth = 1)
        self.stop_frame.grid (row = 0, column = 2, padx = 1, pady = 1)
        self.stop_button = Button (self.stop_frame, text = "stop", fg = "red", command = lambda: self.play(0))
        self.stop_button.pack()

    def process(self, trig):
        self.trig = trig

        while True:
            if self.trig == 1:

                for i in range (10):
                    time.sleep(0.5)
                    print (i)


            elif self.trig == 0:
                print ("stopped...")
                break

    def play(self, switch):


        self.switch = int(switch)
        t1 = threading.Thread (target = self.process, args = [self.switch], daemon = True)
        t1.start()
        

root = Tk()

app = gui(root)
root.mainloop()

Solution

  • Just create a separate thread that receives a signal when to start and stop the countdown

    from tkinter import *
    import threading
    import time
    
    
    should_run = False
    class a:
        def __init__(self):
            while True:
                if should_run:
                    for i in range(10):
                        if not should_run:
                            print('Stopped...')
                            break
                        if should_run:
                            time.sleep(0.5)
                            print(i)
    
    t1 = threading.Thread(target=a,daemon=True)
    t1.start()
    
    class gui:
    
        def __init__(self, window):
    
            # play button
            self.play_frame = Frame(master=window, relief=FLAT, borderwidth=1)
            self.play_frame.grid(row=0, column=0, padx=1, pady=1)
            self.play_button = Button(self.play_frame, text="play", fg="blue", command=lambda: self.play(True))
            self.play_button.pack()
            # stop button
            self.stop_frame = Frame(master=window, relief=FLAT, borderwidth=1)
            self.stop_frame.grid(row=0, column=2, padx=1, pady=1)
            self.stop_button = Button(self.stop_frame, text="stop", fg="red", command=lambda: self.play(False))
            self.stop_button.pack()
    
    
        def play(self, switch):
            global should_run
            should_run = switch
    
    
    
    root = Tk()
    
    app = gui(root)
    root.mainloop()