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)
Related
I am trying to get a button in one function to close the window generated from another function. Here is a shortened version of the code. Basically I want the top window generated from add_drink to be closed when the close_button is clicked at the save_drink stage. How can I do this?
def save_drink(added_drink):
drinks_list = []
newtop = Toplevel(root)
newtop.geometry("200x200")
newtop.title("Drink Added")
label = Label(newtop, text= "{} Added".format((added_drink.get())), font=('Mistral 10')).pack()
close_button = Button(newtop, text="Close", command=newtop.destroy)
close_button.pack()
drinks_list.append(added_drink.get())
def add_drink():
top = Toplevel(root)
top.geometry("750x250")
top.title("Record Drink")
label = Label(top, text= "What drink did you have?", font=('Mistral 18')).pack()
added_drink = Entry(top, font=6)
added_drink.pack()
added_drink_button = Button(top, text='Add Drink', font=3,
command=lambda: save_drink(added_drink)).pack()
You could try passing top from add_drink as a parameter to save_drink
added_drink_button = Button(
top,
text='Add Drink',
font=3,
command=lambda top=top: save_drink(added_drink, top) # add top to the lambda
).pack()
then modify save_drink to accept the top parameter and dispose of it accordingly
in a new function that handles closing both Toplevel widgets
def save_drink(added_drink, top): # add 'top' here
drinks_list = []
newtop = Toplevel(root)
newtop.geometry("200x200")
newtop.title("Drink Added")
label = Label(
newtop,
# I suspect there's some extra parentheses around 'format'
text= "{} Added".format((added_drink.get())), font=('Mistral 10')
).pack()
close_button = Button(
newtop,
text="Close",
# call the 'close' function using a lambda to pass args
command=lambda t=top, n=newtop: close(t, n)
)
close_button.pack()
drinks_list.append(added_drink.get())
This function will close both windows when called by close_button
def close(top, newtop): # pass both windows as parameters
top.destroy()
newtop.destroy()
This should work, though I suspect it might be easier to wrap both the add_drink and save_drink functions in a simple class so they can share information more easily.
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()
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
from tkinter import *
main = Tk()
def flipper(event):
# I'd like to do this:
#if widgetname == switcher:
#do stuff
#if widgetname == switcher1:
#do stuff
return
switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)
switcher1 = Label(main, bg='white', text="click here", font="-weight bold")
switcher1.grid()
switcher1.bind("<Button-1>", flipper)
switcher2 = Label(main, bg='white', text="click here", font="-weight bold")
switcher2.grid()
switcher2.bind("<Button-1>", flipper)
switcher3 = Label(main, bg='white', text="click here", font="-weight bold")
switcher3.grid()
switcher3.bind("<Button-1>", flipper)
switcher4 = Label(main, bg='white', text="click here", font="-weight bold")
switcher4.grid()
switcher4.bind("<Button-1>", flipper)
switcher5 = Label(main, bg='white', text="click here", font="-weight bold")
switcher5.grid()
switcher5.bind("<Button-1>", flipper)
main.mainloop()
In my event function I'd like to do different things based on the label that is clicked. What im stumped on is that I can only get the identifier number of the widget that is clicked, not the name. If I could get the identifier of all my widgets then I could do:
def flipper(event):
if event.widget == switcher.identifier():
do stuff
but I can't find how to get the id of a specified widget either...
How can I get the name of a widget by its identifier (event.widget())?
Or how can I get the identifier of a specified widget name?
If neither are possible, then I'd have to make a different function and bind for each label which is a lot of work that hopefully is not necessary.
Edit:
from tkinter import *
main = Tk()
def flipper(event, switch):
if switch.widget == 's1':
print("got it")
switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)
switcher.widget = 's1'
main.mainloop()
You can't get the variable name that the widget is assigned to, that would be relatively useless. A widget could be assigned to more than one variable, or none at all.
Getting the label text
You have access to the actual widget, and you can use that to get the text that is on the label. Your example shows that all labels are the same, so this might not be useful to you:
def flipper(event):
print("label text:", event.widget.cget("text"))
Using a custom widget name
You can also give a widget a name. You can't get back precisely the name, but you can come very close. For example, if you create a label like this:
switcher = Label(main, name="switcher", bg='white', text="click here", font="-weight bold")
You can get the string representation of the widget by splitting on "." and taking the last value:
def flipper(event):
print("widget name:", str(event.widget).split(".")[-1])
Passing a name via the binding
Finally, you can set up your bindings such that the name is sent to the function:
switcher.bind("<Button-1>", lambda event: flipper(event, "switcher"))
switcher1.bind("<Button-1>", lambda event: flipper(event, "switcher1"))
You can use event.widget to get standard parameters from clicked widget
example:
import tkinter as tk
def callback(event):
print(event.widget['text'])
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)
main.mainloop()
You can assign own variables to widgets
switcher.extra = "Hello"
and then get it
event.widget.extra
example:
import tkinter as tk
def callback(event):
print(event.widget['text'])
print(event.widget.extra)
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)
switcher.extra = "Hello"
main.mainloop()
You can use lambda to bind function with arguments
bind("<Button-1>", lambda event:callback(event, "Hello"))
example:
import tkinter as tk
def callback(event, extra):
print(event.widget['text'])
print(extra)
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", lambda event:callback(event, "Hello"))
main.mainloop()
I had the same issue I found easy way was to use bind method.
apparent name property is private but can be accessed via _name
This is useful if you plan to generate widgets dynamically at runtime
# Import Module
from tkinter import *
# create root window
root = Tk()
# root window title and dimension
root.title("Welcome to Test window")
# Set geometry (widthxheight)
root.geometry('350x200')
#adding a label to the root window
lbl = Label(root, text = "Press a button")
lbl.grid()
#define mouse up event
def mous_up(ev:Event):
#get calling widget from event
sender:Button = ev.widget
#set label text
lbl.configure(text = sender._name + " up")
#read foreground color from button
#If red make green, else make red
if sender.cget('fg') == "red":
#normal color
sender.configure(fg='lime')
#mouse over color
sender.configure(activeforeground='green')
else:
#normal color
sender.configure(fg="red")
#mouse over color
sender.configure(activeforeground='darkred')
#define mouse down event
def mous_down(ev:Event):
lbl.configure(text = str(ev.widget._name) + " down")
# button widget with red color text
# inside
btn = Button(root, text = "Click me" ,
fg = "red",name = "button-A")
#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)
# set Button grid
btn.grid(column=0, row=1)
#Create another button
btn = Button(root, text = "Click me2" ,
fg = "red",name="button2")
#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)
#absolute placement of button instead of
#using grid system
btn.place(x=50,y=100)
# all widgets will be here
# Execute Tkinter
root.mainloop()
Quick and dirty - you could have the function check a switcher attribute.
def flipper(event, switch):
if switch.widget == 's1':
do_stuff
return stuff
if switch.widget == 's2':
do_stuff
return stuff
switcher1.widget = 's1'
switcher2.widget = 's2'
I know this is an old post, but I had the same problem and I thought I should share a solution in case anyone is interested. You can give your widget a name by creating a subclass of the widget. E.g. "Button" is a widget. You can make a child widget "MyButton" which inherits from button and then add an instance variable to it (e.g. name, uniqueID etc.)
Here is a code snippet
class MyButton(Button):
def __init__(self, master = None, textVal = "", wName = ""):
Button.__init__(self, master, text = textVal)
self.widgetID = wName #unique identifier for each button.
When you want to create a new button widget, use
b = MyButton(.....),
instead of
b = Button(.......)
This way, you have all the functionality of a button, plus the unique identifier.
In the program I made, the user presses enter and the text typed is then shown as a label in the program. So the label keeps getting updated and then written on the next line. The problem is that in the textbox the previous line the user typed stays there, which means u have to keep manually deleting the string in the textbox to write a new line. How can I make it so that you start out with a cleared textbox? Also, the enter button works but it seems that when i click on the "Return" button it gives me an error:
TypeError: evaluate() missing 1 required positional argument: 'event'
Here's the code:
from tkinter import *
window = Tk()
window.geometry("200x300")
def evaluate(event):
thetext = StringVar()
labeloutput = Label(app, textvariable = thetext)
n = e.get()
thetext.set(n)
labeloutput.grid()
app = Frame(window)
app.pack()
e = Entry(window)
e.pack()
b= Button(window, text="Return", command=evaluate)
b.pack()
window.bind("<Return>", evaluate)
mainloop()
Since you bind evaluate as a callback and you use it as a button command, when you use it in the button you have to use a lambda and pass None to the event. event argument is needed because of the binding, but there is no event when you call it from button click, so just pass None to get rid of the error. You can delete by doing entry.delete(0, 'end').
from tkinter import *
window = Tk()
window.geometry("200x300")
def evaluate(event):
thetext = StringVar()
labeloutput = Label(app, textvariable = thetext)
n = e.get()
thetext.set(n)
labeloutput.grid()
e.delete(0, 'end') # Here we remove text inside the entry
app = Frame(window)
app.pack()
e = Entry(window)
e.pack()
b = Button(window, text="Return", command=lambda: evaluate(None)) # Here we have a lambda to pass None to the event
b.pack()
window.bind("<Return>", evaluate)
mainloop()
Of course, if you want to prevent the lambda from being used, you would have to create a function to handle the key binding, and a separate one for the button click.