OddlySpecific
OddlySpecific

Reputation: 59

Loop triggered by Tkinter button and ended by another

The following code will show a small Tkinter user interface, however my buttons will not trigger the loop called copy_loop. I have been trying for several hours and I cannot figure out how to fix this. Any help will be very appreciated.

import tkinter as tk
import threading

class App():
    def __init__(self, master):
        self.isrunning = False

        self.button1 = tk.Button(main, text='start')
        self.button1.bind = ("<Button-1>", self.startrunning)
        self.button1.pack()

        self.button2 = tk.Button(main, text='stop')
        self.button2.bind = ("<Button-1>", self.stoprunning)
        self.button2.pack()

    def startrunning(self, event):
        self.isrunning = True
        t = threading.Thread(target=self.copy_loop)
        t.start()

    def stoprunning(self, event):
        self.isrunning = False

    def copy_loop(self):
        while self.isrunning:
            print("Running...")

main = tk.Tk()
app = App(main)
main.mainloop()

Upvotes: 0

Views: 85

Answers (2)

kindall
kindall

Reputation: 184365

bind is a function, not an attribute. Where you have:

self.button1.bind = ("<Button-1>", self.startrunning)

you are actually overwriting the bind function on your instance. It is now a tuple.

Instead, do:

self.button1.bind("<Button-1>", self.startrunning)

And likewise for button2.

Upvotes: 2

Novel
Novel

Reputation: 13729

You have an equals sign where there shouldn't be one. The command should be:

self.button1 = tk.Button(main, text='start')
self.button1.bind("<Button-1>", self.startrunning)

Or the much neater:

self.button1 = tk.Button(main, text='start', command=self.startrunning)

And your method signatures should have event=None:

def startrunning(self, event=None):

Or even more flexible:

def startrunning(self, *args):

Upvotes: 2

Related Questions