Davies
Posts: 150
Joined: Sat Apr 04, 2015 4:24 pm

Stop Button to stop active thread

Mon Jun 15, 2015 12:42 pm

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()
Last edited by Davies on Mon Jun 15, 2015 2:08 pm, edited 2 times in total.

scotty101
Posts: 3958
Joined: Fri Jun 08, 2012 6:03 pm

Re: Stop Button to stop part of code

Mon Jun 15, 2015 1:38 pm

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()

Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Davies
Posts: 150
Joined: Sat Apr 04, 2015 4:24 pm

Re: Stop Button to stop part of code

Mon Jun 15, 2015 1:48 pm

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

scotty101
Posts: 3958
Joined: Fri Jun 08, 2012 6:03 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 2:09 pm

Exit kills the python process but doesn't destroy the Tkinter window.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Davies
Posts: 150
Joined: Sat Apr 04, 2015 4:24 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 2:11 pm

ok, thank you.
do you know how I would be able to kill the "script" thread?

scotty101
Posts: 3958
Joined: Fri Jun 08, 2012 6:03 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 2:18 pm

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.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Davies
Posts: 150
Joined: Sat Apr 04, 2015 4:24 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 2:27 pm

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.

scotty101
Posts: 3958
Joined: Fri Jun 08, 2012 6:03 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 2:58 pm

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.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Davies
Posts: 150
Joined: Sat Apr 04, 2015 4:24 pm

Re: Stop Button to stop active thread

Mon Jun 15, 2015 3:18 pm

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()

Return to “Python”