how to correctly disable tkinter button - python

I have assigned a function to my ttk button and I'm trying to disable the button before do_something_else() runs:
def do_something():
button.config(state='disabled')
do_something_else()
button = ttk.Button(mainframe, text="Click Me", command=do_something, state="normal")
The above doesn't disable the button until do_something_else() is finished. How do I disable correctly? The behavior I want to achieve is to disable the button -> run do_something_else() - > re-enable the button.
EDIT
Accepted answer is correct, for more details refer to Tkinter Button still responds to click after being disabled and updated

You can call button.update_idletasks() to force tkinter to refresh the display.

Related

Exit Python Tkinter app cleanly while also using "wait_variable" function on a button in an "after" loop

I have a problem similar to this post: Exit program within a tkinter class
My variation on the problem involves the wait_variable being used on a button to control "stepping forward" in an app, but also allowing the app to close cleanly.
See my code below:
# To see output unbuffered:
# python -u delete_win_test.py
import tkinter as tk
from tkinter import *
class GUI(Tk):
def __init__(self):
super().__init__()
# Close the app when the window's X is pressed
self.protocol("WM_DELETE_WINDOW", self.closing)
# When this var is set to 1, the move function can continue
self.var = tk.IntVar()
# Close the app if the button is pressed
button = tk.Button(self, text="Exit",
command=self.destroy)
button.place(relx=.5, rely=.5, anchor="c")
# Step forward
self.step_button = tk.Button(self, text="Step",
command=lambda: self.var.set(1))
self.step_button.place(relx=.5, rely=.75, anchor="c")
def move(self):
print("doing stuff") # simulates stuff being done
self.step_button.wait_variable(self.var)
self.after(0, self.move)
def closing(self):
self.destroy()
app = GUI()
app.move()
app.mainloop()
The window shows correctly
"Stepping forward" works because "doing stuff" prints to terminal on button click
Exiting the window by both pressing X or using the "exit" button both work
The problem: the Python app never exits from the terminal and requires a closing of the terminal.
How can I make the Python program exit cleanly so the user does not need to close and re-open a new terminal window?
Related references for animation, etc:
Animation using self.after: moving circle using tkinter
Button wait: Making Tkinter wait untill button is pressed
The original "exit" code: Exit program within a tkinter class
UPDATE (the solution):
(Credit to both response answers below)
# Close the app if the button is pressed
button = tk.Button(self, text="Exit",
- command=self.destroy)
+ command=self.closing)
button.place(relx=.5, rely=.5, anchor="c")
# Step forward
...
def closing(self):
self.destroy()
+ self.var.set("")
+ exit(0)
This allows the native window's "X" to close the window and the Tk button to close the window while still closing the Python app cleanly in the terminal.
Your closing function needs to set the variable to cause the app to stop waiting.
def closing(self):
self.destroy()
self.var.set("")
in the closing function, you need to call exit to exit the program.
def closing(self):
self.destroy() #closes tkinkter window
exit(0) #exits program

Disable button in Tkinter (Python)

Hi , I have some question to ask
I just want to disable the button when i start my program
in attached image, it looks like the button is already disabled ,but its response to my click event or keyboard event
What should i do ?
Thank you for all answer
from Tkinter import *
def printSomething(event):
print("Print")
#Start GUI
gui = Tk()
gui.geometry("800x500")
gui.title("Button Test")
mButton = Button(text="[a] Print",fg="#000",state="disabled")
mButton.place(x=5,y=10)
mButton.bind('<Button-1>',printSomething)
gui.bind('a',printSomething)
gui.mainloop()
You need to unbind the event. state="disabled"/state=DISABLED makes button disabled but it doesn't unbind the event. You need to unbind the corresponding events to achieve this goal. If you want to enable the button again then you need to bind the event again. Like:
from Tkinter import *
def printSomething(event):
print("Print")
#Start GUI
gui = Tk()
gui.geometry("800x500")
gui.title("Button Test")
mButton = Button(text="[a] Print",fg="#000",state="disabled")
mButton.place(x=5,y=10)
mButton.bind('<Button-1>',printSomething)
mButton.unbind("<Button-1>") #new line added
gui.bind('a',printSomething)
gui.mainloop()

Tkinter Button Function Control by MessageBox

The code below shows part of my program and the issue im facing.
def checkAnswer():
mainAnswer = answer01.get()
if len(mainAnswer) == 0:
messagebox.showwarning(message='Please answer the question!')
return
if int(mainAnswer) != answer:
messagebox.showwarning(message='Incorrect! The correct answer is: ' + str(answer))
else:
nxtquest.config(state=NORMAL)
messagebox.showinfo(message='Correct! :)')question01 = Label(easy)
question01.grid(row=2, column=0)
answer01 = Entry(easy)
answer01.grid(row=3, column=2)
answer01.bind('<Return>', func=lambda e:checkAnswer())
start = Button(easy, text = "Start!", command=ask, bg='green', fg='white')
start.grid(row=3, column=3)
nxtquest = Button(easy, text='Next Question', command=ask)
nxtquest.grid(row=5, column=2)
checkbut = Button(easy, text='Check', command=checkAnswer)
checkbut.grid(row=4, column=2)
#check button and answer01 enabled after start pressed
launch = 1
if launch == 1:
answer01.config(state=DISABLED)
checkbut.config(state=DISABLED)
nxtquest.config(state=DISABLED)
The issue which im struggling here is that whenever i run the program everything is okay. When the window is displayed checkbut, nxtquest and label answer01 are greyed out (disabled).
The start button enables only checkbut and answer01 and then is destroyed. (So far so good)
So nxtquest will enable once the input is correct as seen in the
else:
nxtquest.config(state=NORMAL)
But when I reach another question the nxtquest button is already enabled, this is the problem!
How could I make it so the button will enable itself only after the warning message box is displayed?
Could I ask for some help with this and possibly suggestions if you see any rookie mistakes ?
Whilst I don't know of any way you could do this with a messagebox widget (although I'm sure there's an event you could use as the trigger) you can most certainly do this by substituting the messagebox with a Toplevel widget and using .protocol("WM_DELETE_WINDOW", callback()) on the widget.
This would mean that whenever the Toplevel widget was "closed" we would actually be overwriting the action taken when the event was raised and would manually handle the closing of the widget as well as whatever else we wanted it to do.
This would look something like the below:
from tkinter import *
root = Tk()
button = Button(root, text="Ok", state="disabled")
button.pack()
top = Toplevel(root)
def close():
top.destroy()
button.configure(state="active")
top.protocol("WM_DELETE_WINDOW", close)
root.mainloop()
If you close the Toplevel widget you will see that the button is now active instead. This would equally work if we added a Button to the Toplevel widget which called the function close().

Python tkinter raise exceptions and wait for button press

I'm new in Tkinter and I'm currently trying to create a small game. When something happens in the game I want to create a pop-up window which will inform the user about any changes. This is the code that I have written for it.
def message(self, text):
top = tkinter.Toplevel(width=50, height=25)
top.title("Message")
msg = tkinter.Message(top, text=text)
msg.pack()
ok = tkinter.Button(top, text="OK", command=top.destroy)
ok.pack()
My two questions are:
Can I replace this by an exception that will create an "Error Message" window? If it isn't necessary then can I use it to be raised by the exception?
I want the user to be forced to see and read the message, so how can I freeze the main window(the user can't click on anything else) until he presses the OK button on the pop-up window?
Use:
top.grab_set()
To show Error Message you can use tkmessagebox.showerror().

Change command Method for Tkinter Button in Python

I create a new Button object but did not specify the command option upon creation. Is there a way in Tkinter to change the command (onclick) function after the object has been created?
Though Eli Courtwright's program will work fine¹, what you really seem to want though is just a way to reconfigure after instantiation any attribute which you could have set when you instantiated². How you do so is by way of the configure() method.
from Tkinter import Tk, Button
def goodbye_world():
print "Goodbye World!\nWait, I changed my mind!"
button.configure(text = "Hello World!", command=hello_world)
def hello_world():
print "Hello World!\nWait, I changed my mind!"
button.configure(text = "Goodbye World!", command=goodbye_world)
root = Tk()
button = Button(root, text="Hello World!", command=hello_world)
button.pack()
root.mainloop()
¹ "fine" if you use only the mouse; if you care about tabbing and using [Space] or [Enter] on buttons, then you will have to implement (duplicating existing code) keypress events too. Setting the command option through .configure is much easier.
² the only attribute that can't change after instantiation is name.
Sure; just use the bind method to specify the callback after the button has been created. I've just written and tested the example below. You can find a nice tutorial on doing this at http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
from Tkinter import Tk, Button
root = Tk()
button = Button(root, text="Click Me!")
button.pack()
def callback(event):
print "Hello World!"
button.bind("<Button-1>", callback)
root.mainloop()

Categories

Resources