Disable / Enable Button in TKinter - python

I'm trying to make a button like a switch, so if I click the disable button
it will disable the "Button" (that works). And if I press it again, it will enable it again.
I tried things like if, else but didn't get it to work.
Here's an example:
from tkinter import *
fenster = Tk()
fenster.title("Window")
def switch():
b1["state"] = DISABLED
#--Buttons
b1=Button(fenster, text="Button")
b1.config(height = 5, width = 7)
b1.grid(row=0, column=0)
b2 = Button(text="disable", command=switch)
b2.grid(row=0,column=1)
fenster.mainloop()

A Tkinter Button has three states : active, normal, disabled.
You set the state option to disabled to gray out the button and make it unresponsive. It has the value active when the mouse is over it and the default is normal.
Using this you can check for the state of the button and take the required action. Here is the working code.
from tkinter import *
fenster = Tk()
fenster.title("Window")
def switch():
if b1["state"] == "normal":
b1["state"] = "disabled"
b2["text"] = "enable"
else:
b1["state"] = "normal"
b2["text"] = "disable"
#--Buttons
b1 = Button(fenster, text="Button", height=5, width=7)
b1.grid(row=0, column=0)
b2 = Button(text="disable", command=switch)
b2.grid(row=0, column=1)
fenster.mainloop()

The problem is in your switch function.
def switch():
b1["state"] = DISABLED
When you click the button, switch is being called each time. For a toggle behaviour, you need to tell it to switch back to the NORMAL state.
def switch():
if b1["state"] == NORMAL:
b1["state"] = DISABLED
else:
b1["state"] = NORMAL

Related

Variable of Radiobutton in tkinter Python not working

On this code I'm trying to get working a Settings program, in which you can disable or enable the log. This code renders a Window, with a Settings button, when you press that button, it opens a new window with two Radio Button's (Enable/Disable), and the program should determine the current status of the setting, but I can't get it to work, because the variable (X) determines what option should be selected by default, according to the current status, but it doesn't work. Please help me!.
from msilib.schema import RadioButton
from tkinter import *
import tkinter as asset1
import tkinter
settings = {"overrideAdminReq" : True} # DEFAULT SETTING.
def showLogSettingToFalse(): # WHEN DISABLE BUTTON IS PRESSED.
settings["overrideAdminReq"] = False # SET SETTING TO FALSE.
print("Log was disabled")
def showLogSettingToTrue(): # WHEN ENABLE BUTTON IS PRESSED.
settings["overrideAdminReq"] = True # SET SETTING TO TRUE.
print("Log was enabled")
def showSettings(asset1): # WHEN SETTINGS BUTTON IS PRESSED.
settingsWindow = Tk() # NEW WINDOW
settingsWindow.title("Settings")
settingsWindowGrid = asset1.Frame(settingsWindow, padx=2)
settingsWindowGrid.pack()
x = IntVar() # DEFINES THE VARIABLE
if settings["overrideAdminReq"] == True: y=1 # IF SETTING IS TRUE, DEFINES Y = 1
else: y=2 # IF SETTING IS FALSE, DEFINES Y = 2
x.set(value=y) # SETS THE VALUE OF X WITH Y
print("Log status: "+str(settings["overrideAdminReq"]))
Label(settingsWindowGrid, text="Log Functionality:").grid(row=1,column=0) # TITLE LABEL.
enableFunct = Radiobutton(settingsWindowGrid, # ENABLE OPTION.
text="Enable",
value=1, # OPTION VALUE
variable=x,
command=lambda: showLogSettingToTrue())
enableFunct.grid(row=1,column=1)
disableFunct = Radiobutton(settingsWindowGrid, # DISABLE OPTION.
text="Disable",
value=2, #OPTIONE VALUE
variable=x, #VARIABLE
command=lambda: showLogSettingToFalse())
disableFunct.grid(row=2,column=1)
settingsWindow.mainloop()
w1 = Tk()
button_1 = tkinter.Button(w1, text='Settings', padx=30, pady=5, command=lambda: showSettings(asset1), borderwidth=5)
button_1.grid(row=1, column=0, pady=2)
w1.mainloop()

How to determine which Button was pressed?

I created 5 buttons. When users click the button, new window opens. I want the opened windows have different title. For example users click button1, the window that was opened name will be "Button_1". This is some part of my code.
button1= tk.Button(window,image=photo1,command=Calculations)
button2= tk.Button(window,image=photo2,command=Calculations)
button3= tk.Button(window,image=photo3,command=Calculations)
button4= tk.Button(window,image=photo4,command=Calculations)
button5= tk.Button(window,image=photo5,command=Calculations)
def Calculations():
window_2 = tk.Toplevel()
window_2.geometry("1000x1000")
window_2.title("Button_1")
I think if I know which button is pressed, I think I can assign a variable and write the window_2.title() with the format() method. Is there a way to find the button that was pressed and assign it to a variable or another idea?
You pass the button and its name/index using functools.partial(<command>, *arguments).
from functools import partial
def Calculations(button, name):
window_2 = tk.Toplevel()
window_2.geometry("1000x1000")
window_2.title(name)
# Create the button without a command or an empty command
button1= tk.Button(window, image=photo1)
# Configure the command later so that we can also pass in `button1` to the function
button1.config(command=partial(Calculations, button1, "button1"))
button2 = tk.Button(window, image=photo2)
button2.config(command=partial(Calculations, button2, "button2"))
...
You can use a lambda function for the button's command argument.
button1= tk.Button(window,image=photo1,command=lambda: Calculations("1"))
button2= tk.Button(window,image=photo2,command=lambda: Calculations("2"))
button3= tk.Button(window,image=photo3,command=lambda: Calculations("3"))
button4= tk.Button(window,image=photo4,command=lambda: Calculations("4"))
button5= tk.Button(window,image=photo5,command=lambda: Calculations("5"))
def Calculations(num):
window = tk.Toplevel()
window.geometry("1000x1000")
window.title("Button_" + num)
A more efficient solution would be to use a for loop:
for i in range(5):
i += 1
globals()["button" + str(i)] = tk.Button(window, image=globals()["photo" + str(i)], command=lambda i=i: Calculations(str(i)))
def Calculations(num):
window = tk.Toplevel()
window.geometry("1000x1000")
window.title("Button_" + num)
button1= tk.Button(window,image=photo1,command=lambda: Calculations("button one"))
button2= tk.Button(window,image=photo2,command=lambda: Calculations("button two"))
button3= tk.Button(window,image=photo3,command=lambda: Calculations("button three"))
button4= tk.Button(window,image=photo4,command=lambda: Calculations("button four"))
button5= tk.Button(window,image=photo5,command=lambda: Calculations("button 5"))
so then when the button is pressed it will give a str variable which says which button was pressed. Example: "button one"
def Calculations(button):
window = tk.Toplevel()
window.geometry("1000x1000")
window.title(str(button))
then the title of the window will be which button was pressed.
you could also make a set of radio buttons/ check buttons and assign them to tk.IntVar() and make a unique value for each of them and make a 'done' button.
( it does the same thing expect that it will be check buttons)
var = tk.IntVar()
C1 = tk.Checkbutton(frame, onvalue=1, variable=self.var)
C2 = tk.Checkbutton(frame, onvalue=2, variable=self.var)
C3 = tk.Checkbutton(frame, onvalue=3, variable=self.var)
C4 = tk.Checkbutton(frame, onvalue=4, variable=self.var)
done = tk.button(frame, command=calculations)
def Calculations(num):
window = tk.Toplevel()
window.geometry("1000x1000")
window.title("Button_" + var)

Call variables in function by adding to variable number?

I'm Creating a gui in tkinter and have buttons named btn1 btn2 btn3 etc, what i want the button to do on click is disable the button clicked and enable the next button in order. I can write out 6 seperate functions but that seems to defeat the point of a function.
if (btn1['state'] == tk.NORMAL):
btn1.config(state=tk.DISABLED),
btn2.config(state=tk.NORMAL)
else: print ('already clicked')
this is what i have now, but i want it to look more like btn #+1 (state=DISABLED)
You can put the buttons in a list, and then iterate over the list.
Here's a bit of a contrived example:
import tkinter as tk
root = tk.Tk()
def click(button_number):
button = buttons[button_number]
button.configure(state="disabled")
if button == buttons[-1]:
# user clicked the last button
label.configure(text="BOOM!")
else:
next_button = buttons[button_number+1]
next_button.configure(state="normal")
next_button.focus_set()
label = tk.Label(root, text="")
label.pack(side="bottom", fill="x")
buttons = []
for i in range(10):
state = "normal" if i == 0 else "disabled"
button = tk.Button(root, text=i+1, state=state, width=4,
command=lambda button_number=i: click(button_number))
button.pack(side="left")
buttons.append(button)
buttons[0].focus_set()
root.mainloop()

Tkinter GUI program issue. Entry.get() problem

Working on a project in which I use Tkinter in order to create a GUI that gives a list of software in a drop-down and when a particular software is chosen, it takes you to a separate window where a user's name will be entered and they would be added to a database. With the code I have so far, I am able to link a "submit" button on the second window to a function that prints a confirmation message as a test to make sure the button works. My issue now is trying to get the input from the entry field and link the input to the "Submit" button but I can't seem to find a way to do so. I was wondering if I could get some advice on how to go about this. Would classes need to be used in order to make it work? or can I stick with functions and keep the code relatively simple?
I have added the code for my program below.
import tkinter as tk
from tkinter import *
from tkinter import ttk
root = tk.Tk() # Main window
root.title("Software Licences")
root.geometry("300x300")
frame = ttk.Frame(root, padding="50 0 50 50")
frame.pack(fill=tk.BOTH, expand=True)
tkvar = StringVar()
choices = ['Imagenow', # Dropdown menu with software options
'FileMakerPro',
'Acrobat',
'Office',
'Lotus Notes']
tkvar.set('Acrobat') # Shows default dropdown menu option when program is opened
popupMenu = OptionMenu(frame, tkvar, *sorted(choices))
popupLabel = ttk.Label(frame, text="Choose Software")
popupLabel.pack()
popupMenu.pack()
def software_pages(): # In this function is the 2nd window with for each individual software
top = Toplevel()
top.title("Software Licences")
top.geometry("300x300")
myLabel = Label(top, text=tkvar.get()).pack()
employee_entrylbl = Label(top, text="Employee name").pack()
employee_entry = Entry(top, width=25, textvariable=tk.StringVar) # Entry field for adding user's name
employee_entry.pack() # Entry field is displayed
if tkvar.get() == "Acrobat": # for each if statement, button command is link to the functions
# defined below
button = ttk.Button(top, text="Submit", command=add_to_acrobat).pack()
elif tkvar.get() == "Imagenow":
button = ttk.Button(top, text="Submit", command=add_to_imagenow).pack()
elif tkvar.get() == "FileMakerPro":
button = ttk.Button(top, text="Submit", command=add_to_filemakerpro).pack()
elif tkvar.get() == "Office":
button = ttk.Button(top, text="Submit", command=add_to_office).pack()
else:
button = ttk.Button(top, text="Submit", command=add_to_lotusnotes).pack()
exit_button = ttk.Button(top, text="Exit", command=top.destroy).pack() # Exit button for second window
add_emp_button = ttk.Button(frame, text="Next", command=software_pages) # "Next" button in the main window takes the
# user to the second window
add_emp_button.pack()
# Functions below are linked to the button commands of each software in the second window function defined earlier.
# They print out specified messages that confirm the user had been added
def add_to_acrobat():
return print("User added to Acrobat")
def add_to_lotusnotes():
print("User added to IBM")
def add_to_imagenow():
print("User added to imagenow")
def add_to_office():
print("User added to 365")
def add_to_filemakerpro():
print("User added to FMP")
def click_button(): # Function for Exit button for main window
root.destroy()
exit_button = ttk.Button(frame, text="Exit", command=click_button) # Exit button for main window
exit_button.pack()
root.mainloop()
You can pass parameters to the command of tkinter.command using partial from the functools module.
in your case:
button = ttk.Button(top, text="Submit", command=partial(add_to_acrobat, employee_entry)).pack()
in the above line, I send the employee_entry(Which holds your desired text) to the add_to_acrobat function
and the add_acrobat function should look like this:
def add_to_acrobat(e):
print(e.get())
return print("User added to Acrobat")
Hope it helps

Self Made Tkinter Popup Menu Python

I was writing a GUI library in Python based on tkinter and I was designing and building all the widgets, but I have come to the PopUp menus.
Due that tkinter picks system menus and this can't be customized, I write the following code to make a frame where I can put my customized buttons in and works as a popup.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.place(x=0)
def function1():
print('function1 activated')
# create a menu
f = Frame(root,width=80,height=60,background='green')
b2 = Button(f,text='function',command=function1)
b2.pack()
def open_popup(event):
try:
f.place(x=event.x, y=event.y)
root.after(1)
f.focus_set()
w.bind_all("<Button-1>",close_popup)
except:
print("Can't open popup menu")
def close_popup(event):
try:
f.place_forget()
root.after(1)
w.unbind_all("<Button-1>")
except:
print("Can't close popup menu")
w.bind("<Button-3>", open_popup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
Everything works well, if I clicked with the mouse right-button the popup menu appears, and if I clicked on every other part the popup menu dissapears.
The problem is that, due to bind_all when I press the button of my popup menu, function1 doesn't run and the event handler closes the popup. I have tried with only bind but this time, function1 runs and the event handler doesn't activates.
Is there anyway I can do that?
Thanks
I would do this using a tracking variable.
We can first assign None to f as a way to check if f is currently set up.
If f is not None then we create frame and button. Then when the function is activated we can run function and destroy the frame the button was in. This also destroys the button and then we set f back to None for out next use.
Take a look at the below reworked example.
Let me know if you have any questions.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.place(x=0)
f = None # Tracking F to see if it is None or not.
def function1():
global f
print('function1 activated')
# add this to the end of the function to destroy the frame and reset f
if f != None:
f.destroy()
f = None
def open_popup(event):
global f
# if f is None then create frame and button else don't
if f == None:
f = Frame(root,width=80,height=60,background='green')
f.place(x=event.x, y=event.y)
b2 = Button(f,text='function',command=function1)
b2.pack()
else:
print("Can't open popup menu")
w.bind("<Button-3>", open_popup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
I found a way to do this without modifying so much the code, the idea of the tracking variable was good but doesn't solve all the problems, and this code does.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.pack()
def function1():
print('function1 activated')
try:
f.place_forget()
except:
pass
# create a menu
f = Frame(root,width=80,height=60,background='green')
b2 = Button(f,text='function',command=function1)
b2.place(x=0,y=5)
def open_popup(event):
try:
f.place(x=event.x, y=event.y)
root.after(1)
f.focus_set()
except:
pass
def close_popup(event):
try:
f.place_forget()
root.after(1)
w.unbind_all("<Button-1>")
except:
pass
def enable_depopup(event):
w.bind_all("<Button-1>",close_popup)
def disable_depopup(event):
w.unbind_all("<Button-1>")
w.bind("<Button-3>", open_popup)
w.bind("<Motion>", enable_depopup)
f.bind("<Motion>", disable_depopup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
In this way, everytime I move the mouse over the parent window, the <Button-1> of the mouse is binded to close the popup menu.
And doing a trick, that is place the button of the menu a few pixels down, this let the mouse pass through the popup frame to reach the button and disable the <Button-1> binding letting me click the button.
The function of the button activate the place_forget method of the frame, so everything works correctly.

Categories