Skip to content
Advertisement

Tkinter – TTK – Button change state after click

how can i change the state of a button made with TTK in Python after i clicked it ? I want to disable the button START after i press it once and re-enable it after pressing STOP. I want this because my code creates a new duplicated thread everytime i press Start … so… i want to disable it… I used TTK instead of TK cause i saw it looks better but i cant seem to figure out how to use a global variable that just flips the state of that START button after i press it …

Example :

frm2=ttk.Button(frm, text="Start", command=start_button).grid(column=0, row=3)

This is my entire script so you can run it yourself and see what i mean …

from tkinter import *
from tkinter import ttk
import pyautogui
import keyboard
import time
import threading

gvar = False

def imagedetect():
    while gvar:
        if pyautogui.locateOnScreen('image.png', confidence = 0.9) != None:
            print("I can see it")
            time.sleep(1)
        else:
            print("I am unable to see it")
            time.sleep(1)
    #root.after(1000,imagedetect)

def start_button():
    global gvar
    gvar = True
    th_runner = threading.Thread(target=imagedetect, daemon=True)
    th_runner.start()

def on_start():
    global gvar
    gvar = True
def on_stop():
    global gvar
    gvar = False

def help():
    filewin = Toplevel(root, padx=50,pady=50)
    information = Label(filewin, text="App made by ..... you can close the app after starting it by pressing the key Q")
    information.pack()


root = Tk()
root.title("Rename me later")

menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Help", command=help)
filemenu.add_separator()
menubar.add_cascade(label="Info", menu=filemenu)


frm = ttk.Frame(root, padding=30)
frm.pack()


ttk.Label(frm, text="App made by uknown").grid(column=1, row=0)

frm2=ttk.Label(frm, text="").grid(column=0, row=1)
frm2=ttk.Label(frm, text="").grid(column=1, row=1)
frm2=ttk.Label(frm, text="").grid(column=2, row=1)

frm2=ttk.Label(frm, text="").grid(column=0, row=2)
frm2=ttk.Label(frm, text="").grid(column=1, row=2)
frm2=ttk.Label(frm, text="").grid(column=2, row=2)

frm2=ttk.Button(frm, text="Start", command=start_button).grid(column=0, row=3)
frm2=ttk.Button(frm, text="Stop", command=on_stop).grid(column=1, row=3)
frm2=ttk.Button(frm, text="Quit", command=root.destroy).grid(column=2, row=3)
#root.destroy
root.config(menu=menubar)
#imagedetect()
root.mainloop()

Advertisement

Answer

Why did you use the same variable for multiple widgets? It doesn’t work like that because a variable can only contain one value. If you want to change the button state later then you have to have separate variable names. Also you first have to create a button and then grid it. Not doing them in one line because you see grid returns none so that means you actually stored none in the variable instead of the widget class.

To change the state of button you do this btn.config(state=DISABLED OR NORMAL)

This should work:

from tkinter import *
from tkinter import ttk
import pyautogui
import keyboard
import time
import threading

gvar = False

def imagedetect():
    while gvar:
        if pyautogui.locateOnScreen('image.png', confidence = 0.9) != None:
            print("I can see it")
            time.sleep(1)
        else:
            print("I am unable to see it")
            time.sleep(1)
    #root.after(1000,imagedetect)

def start_button():
    global gvar, btn
    btn.config(state=DISABLED)
    gvar = True
    th_runner = threading.Thread(target=imagedetect, daemon=True)
    th_runner.start()

def on_start():
    global gvar
    gvar = True
def on_stop():
    global gvar
    btn.config(state=NORMAL)
    gvar = False

def help():
    filewin = Toplevel(root, padx=50,pady=50)
    information = Label(filewin, text="App made by ..... you can close the app after starting it by pressing the key Q")
    information.pack()


root = Tk()
root.title("Rename me later")

menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Help", command=help)
filemenu.add_separator()
menubar.add_cascade(label="Info", menu=filemenu)


frm = ttk.Frame(root, padding=30)
frm.pack()


ttk.Label(frm, text="App made by uknown").grid(column=1, row=0)
# You may need to change the names of these variables
frm2=ttk.Label(frm, text="").grid(column=0, row=1)
frm2=ttk.Label(frm, text="").grid(column=1, row=1)
frm2=ttk.Label(frm, text="").grid(column=2, row=1)

frm2=ttk.Label(frm, text="").grid(column=0, row=2)
frm2=ttk.Label(frm, text="").grid(column=1, row=2)
frm2=ttk.Label(frm, text="").grid(column=2, row=2)

btn=ttk.Button(frm, text="Start", command=start_button) # Button is a class not a nonetype
btn.grid(column=0, row=3)
frm2=ttk.Button(frm, text="Stop", command=on_stop).grid(column=1, row=3)
# This below is what 'frm2' will be equal to at the end so other widgets are lost so if need to use them later then you have to have seperate variables
frm2=ttk.Button(frm, text="Quit", command=root.destroy).grid(column=2, row=3)

#root.destroy
root.config(menu=menubar)
#imagedetect()
root.mainloop()
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement