Page 1 of 1

Stop Button to stop active thread

Posted: Mon Jun 15, 2015 12:42 pm
by Davies
hi all, im trying to make a program and id like to add a stop button which will stop the code and reset the form but im having issues getting the stop button to work as I intend.. what id like to do is have "button" start and stop the code, which for this example is a countdown from 5.

Code: Select all

import Tkinter as tk
root = tk.Tk()
from Tkinter import *
import threading
import time


root.geometry("720x100")
root.title("Countdown Tester")

stop = threading.Event()


def reset():
    button["text"] = "Begin Countdown"
    label["text"] = "Countdown Finished"
    label.config(bg='dark red', fg='white')
    label2["text"] = ""
    label2.config(bg='black', fg='white')
    root.timer = root.after(1000, label.update)
    root.update_idletasks()
    stop.set()


def script():
    if not stop.set():
        label["text"] = "Countdown Began"
        label.config(bg='blue', fg='white')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "5"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "4"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "3"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "2"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "1"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "0"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        reset()


def toggle_text():
    if button["text"] == "Begin Countdown":
        button["text"] = "Stop Countdown"
        label["text"] = "Countdown Began"
        label.config(bg='green', fg='black')
        stop.clear()
        t1 = threading.Thread(target=script)
        t1.daemon = True
        t1.start()
    else:
        button["text"] = "Begin Countdown"
        label["text"] = "Countdown Stopped"
        label.config(bg='red', fg='white')
        label2["text"] = ""
        label2.config(bg='black', fg='white')
        stop.set()
    root.update_idletasks()


canvas = Canvas(width=720, height=100, bg='black')
canvas.grid(rowspan=26, columnspan=20, sticky='W,E,N,S')


button = Button(root, text="Begin Countdown", font='-weight bold', width=17, command=toggle_text)
button.grid(padx=10, pady=10, row=10, column=0, sticky='W,E,N,S')
button2 = Button(root, text="   Quit   ", font='-weight bold', command=exit)
button2.grid(padx=5, pady=10, row=10, column=1, sticky='W,E,N,S')

label = Label(root, text=" ", width=20, font='-weight bold', background='black')
label.grid(padx=5, pady=10, row=10, column=2, sticky='W,E,N,S')
label2 = Label(root, text=" ", width=11, font='-weight bold', background='black')
label2.grid(padx=5, pady=10, row=10, column=3, sticky='W,E,N,S')


root.resizable(width=FALSE, height=FALSE)

root.mainloop()

Re: Stop Button to stop part of code

Posted: Mon Jun 15, 2015 1:38 pm
by scotty101
Use the root.destroy function

Code: Select all

import Tkinter as tk
root = tk.Tk()
from Tkinter import *
import threading
import time


root.geometry("720x100")
root.title("Countdown Tester")

stop = threading.Event()


def reset():
    button["text"] = "Begin Countdown"
    label["text"] = "Countdown Finished"
    label.config(bg='dark red', fg='white')
    label2["text"] = ""
    label2.config(bg='black', fg='white')
    root.timer = root.after(1000, label.update)
    root.update_idletasks()
    stop.set()


def script():
    if not stop.set():
        label["text"] = "Countdown Began"
        label.config(bg='blue', fg='white')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "5"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "4"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "3"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "2"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "1"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        time.sleep(1)
        label2["text"] = "0"
        label2.config(bg='orange', fg='black')
        root.update_idletasks()
        reset()


def toggle_text():
    if button["text"] == "Begin Countdown":
        button["text"] = "Stop Countdown"
        label["text"] = "Countdown Began"
        label.config(bg='green', fg='black')
        stop.clear()
        t1 = threading.Thread(target=script)
        t1.daemon = True
        t1.start()
    else:
        button["text"] = "Begin Countdown"
        label["text"] = "Countdown Stopped"
        label.config(bg='red', fg='white')
        label2["text"] = ""
        label2.config(bg='black', fg='white')
        stop.set()
    root.update_idletasks()

def onExit():
    root.destroy()


canvas = Canvas(width=720, height=100, bg='black')
canvas.grid(rowspan=26, columnspan=20, sticky='W,E,N,S')


button = Button(root, text="Begin Countdown", font='-weight bold', width=17, command=toggle_text)
button.grid(padx=10, pady=10, row=10, column=0, sticky='W,E,N,S')
button2 = Button(root, text="   Quit   ", font='-weight bold', command=onExit)
button2.grid(padx=5, pady=10, row=10, column=1, sticky='W,E,N,S')

label = Label(root, text=" ", width=20, font='-weight bold', background='black')
label.grid(padx=5, pady=10, row=10, column=2, sticky='W,E,N,S')
label2 = Label(root, text=" ", width=11, font='-weight bold', background='black')
label2.grid(padx=5, pady=10, row=10, column=3, sticky='W,E,N,S')


root.resizable(width=FALSE, height=FALSE)

root.mainloop()


Re: Stop Button to stop part of code

Posted: Mon Jun 15, 2015 1:48 pm
by Davies
I was lead to believe calling "exit" on a button command was a built in command in python and no need for a def?
my issue is that when I press stop countdown the countdown continues

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 2:09 pm
by scotty101
Exit kills the python process but doesn't destroy the Tkinter window.

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 2:11 pm
by Davies
ok, thank you.
do you know how I would be able to kill the "script" thread?

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 2:18 pm
by scotty101
I've done a bit of looking and there is no official way to stop a thread. There used to be an unofficial _stop() method but that has disappeared now too.

If you just want a timer and aren't too concerned about threading, you can use the tkinter .after() method to trigger an event every second to update the count down.

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 2:27 pm
by Davies
am I correctly calling stop as a threading event? because if I change the "if" statement on "def script" to "while" the countdown continues over and over again even after the threading event has been called.

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 2:58 pm
by scotty101
Do you mean the stop.set() and stop.clear commands?

If so then they don't do what you think they do.

https://docs.python.org/3.2/library/thr ... nt-objects

You might need to change your

Code: Select all

if not stop.set():
to

Code: Select all

if not stop.is_set():
but I'm not sure what you are really trying to do with threads apart from do a countdown which it total over kill.

Re: Stop Button to stop active thread

Posted: Mon Jun 15, 2015 3:18 pm
by Davies
I realised and changed to .isSet
im now able to stop the timer by changing some of my code around..
the code I actually have works gpios and is lengthy, too lengthy than needed for this question and cannot be run in pycharm hence the countdown instead

Code: Select all

import Tkinter as tk
root = tk.Tk()
from Tkinter import *
import threading
import time


root.geometry("720x100")
root.title("Countdown Tester")

stop = threading.Event()


def reset():
    button["text"] = "Begin Countdown"
    label["text"] = "Countdown Finished"
    label.config(bg='dark red', fg='white')
    label2["text"] = ""
    label2.config(bg='black', fg='white')
    root.timer = root.after(1000, label.update)
    root.update_idletasks()
    stop.set()


def _5():
    label2["text"] = "5"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def _4():
    label2["text"] = "4"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def _3():
    label2["text"] = "3"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def _2():
    label2["text"] = "2"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def _1():
    label2["text"] = "1"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def _0():
    label2["text"] = "0"
    label2.config(bg='orange', fg='black')
    root.update_idletasks()
    time.sleep(1)


def script():
    if not stop.isSet():
        label["text"] = "Countdown Began"
        label.config(bg='blue', fg='white')
        root.update_idletasks()
    if not stop.isSet():
        _5()
    if not stop.isSet():
        _4()
    if not stop.isSet():
        _3()
    if not stop.isSet():
        _2()
    if not stop.isSet():
        _1()
    if not stop.isSet():
        _0()
        reset()


def toggle_text():
    if button["text"] == "Begin Countdown":
        button["text"] = "Stop Countdown"
        label["text"] = "Countdown Began"
        label.config(bg='green', fg='black')
        stop.clear()
        t1 = threading.Thread(target=script)
        t1.daemon = True
        t1.start()
    else:
        button["text"] = "Begin Countdown"
        label["text"] = "Countdown Stopped"
        label.config(bg='red', fg='white')
        label2["text"] = ""
        label2.config(bg='black', fg='white')
        stop.set()
    root.update_idletasks()


def on_exit():
    root.destroy()


canvas = Canvas(width=720, height=100, bg='black')
canvas.grid(rowspan=26, columnspan=20, sticky='W,E,N,S')


button = Button(root, text="Begin Countdown", font='-weight bold', width=17, command=toggle_text)
button.grid(padx=10, pady=10, row=10, column=0, sticky='W,E,N,S')
button2 = Button(root, text="   Quit   ", font='-weight bold', command=on_exit)
button2.grid(padx=5, pady=10, row=10, column=1, sticky='W,E,N,S')

label = Label(root, text=" ", width=20, font='-weight bold', background='black')
label.grid(padx=5, pady=10, row=10, column=2, sticky='W,E,N,S')
label2 = Label(root, text=" ", width=11, font='-weight bold', background='black')
label2.grid(padx=5, pady=10, row=10, column=3, sticky='W,E,N,S')


root.resizable(width=FALSE, height=FALSE)

root.mainloop()