How do I pass parameters to a function through a button?
variable = str()
def RandomFunction(variable):
print (variable)
EntryBox = Entry(MainWindow, textvariable = variable).pack()
FunctionCall = Button(MainWindow, text="Enter", command=RandomFunction(variable))
It seems like it just doesnt print anything when the button is pressed. I've searched around and it seems that using lambda can fix it and allow (variable) to be passed to the function but after experimenting with lambda variable:variable I still can't get it to work.
The other answers here work, but like a lot of things in life, there's more than one way to do what you're trying to do.
The code in your question actually mixes a couple of methods of getting data from the Entry widget. You're using textvariable and lambda, but you only need one. It seems like lambda has been covered, so here's a quick answer about textvariable:
First, you need to make your variable of a Tkinter string type like this:
variable = StringVar()
Your entry widget is fine, it's connected to the StringVar(). Your button doesn't need lambda, though, because you don't need to pass an argument to your RandomFunction().
FunctionCall = Button(MainWindow, text='Enter', command=RandomFunction).pack()
Lastly, your function needs a little rework, because it's not taking an argument anymore, it's just going to use the .get() method on your StringVar() whenever it's called:
def RandomFunction():
print(variable.get())
You can read more about StringVar()s here: http://effbot.org/tkinterbook/variable.htm
You use .get() to get the contents of an Entry. From the effbot page http://effbot.org/tkinterbook/entry.htm
from Tkinter import *
master = Tk()
e = Entry(master)
e.pack()
e.focus_set()
def callback():
print e.get()
b = Button(master, text="get", width=10, command=callback)
b.pack()
master.mainloop()
Using lambda to create a function that calls the function with the argument is fine (as long as you do it correctly):
FunctionCall = Button(MainWindow, text="Enter", command=lambda: RandomFunction(EntryBox.get))
Python will be happy with this because the lambda doesn't take any arguments.
Related
I am trying to use tkinter to have a user input variables to pass it into a function. The problem is , the input from the user is not being assigned to the actual variable for whatever reason.
root = Tk()
root.geometry("600x300")
MainWindow = Label(root, text = "Input var:")
MainWindow.grid(row=0, column = 0)
var= Entry(root)
var.grid(row=0, column=1)
I have about 20 variables being asked for in the GUI that has similar code to the above.
I then assign a button to display what is assigned to the variable (for troubleshooting purposes, the original purpose of the button is to pass the variables into a function).
buttonGo=Button(root, text="Generate", command= lambda: print(f'Var is : {var}'))
buttonGo.grid(row=20, column=1)
buttonExit
buttonExit.grid(row=20, column=2)
root.mainloop()
When I run the program and click on the "Generate" button, I get the below output and not what I define it in the program.
Var is : .!entry
That .!entry is the widget, not the value. If you want the value, you need to use the get() method of the widget.
In other words, something like:
value = var.get()
# Now use value.
Based on the replies I got, I believe I found the answer to be using .get method when calling the function. I modified the line to:
buttonGo=Button(root, text="Generate", command= lambda: print(f'Var is : {var.get()}'))
Thanks for the replies and explanations.
I'm trying to make a button that saves your username but then goes away after you set it.
this is my code:
def printValue():
User = Name.player_name.get()
label.config(text=f'Hi, {User}')
Name.button.destroy()
Name.player_name.destroy()
def Name():
label.config(text="What's your name?")
Name.player_name = Entry(root)
Name.player_name.pack(pady=15)
Name.button = Button(text="Change", command=printValue)
Name.button.pack()
The code below, with some minor changes like enabling change with [Return] and some layout cosmetics works OK (also with un-commented lines in printValue) . If you want the [Change] button and the entry area to go away un-comment the two lines turned into comments in the printValue function:
# https://stackoverflow.com/questions/72671126/tkinter-destroying-an-object-in-a-different-function-isnt-working
from tkinter import Tk, mainloop, Entry, Button, Label
root = Tk()
label = Label(root, font=('',12), padx=15, pady=5)
label.pack()
def Name():
label.config(text="What's your name?")
Name.player_name = Entry(root, font=('',12))
Name.player_name.pack(padx=15, pady=15)
Name.player_name.focus()
Name.button = Button(text="Change", command=printValue)
Name.button.pack()
def printValue(event=None):
User = Name.player_name.get()
# Name.player_name.destroy()
# Name.button.destroy()
label.config(text=f'Hi, {User}')
Name()
root.bind("<Return>", printValue)
mainloop()
By the way: The in the question provided code demonstrates an interesting approach of making names of variables global by setting function attributes in the function itself. This way it is possible to assign values in one function and retrieve them in another without passing return values or declaring variables global. I am not aware of already having seen such approach used in Python code here on stackoverflow. How does it come you use such code?
I am trying to create a virtual keyboard using Tkinter and I am trying to do something
analogous to the code supplied below. I am having trouble with understanding the lambda construct in the code below, which from what I understand is the only way to go without having to write a button widget for every single letter that exists on the keyboard.
I have always understood that when you are using lambda, you do something analogous to:
variable = lambda x: x+5
but in the supplied code further down, the Button widget has a lambda I have not seen before written like this:
command=lambda value=text: select(entry, value)
I have spent all day reading about lambda, and I still cannot get this.
This is the code link:
How to call and close a virtual keyboard made by Tkinter using touchscreen display
Specifically this is the line I am having problems with:
tk.Button(window, text=text, width=width,
command=lambda value=text: select(entry, value),
padx=3, pady=3, bd=12, bg="black", fg="white", takefocus = False
).grid(row=y, column=x, columnspan=columnspan)
My problem was that i did not know you could use the default argument on lambda....i am surprised not many picked up how dumb i was though.
command=lambda value=text: select(entry, value)
value or value=text is the same thing if text is a variable. That was
my problem
I am a beginner in python, I used tkinter to build a to-do list program. But the problem is I don't understand how it works.
from tkinter import *
root = Tk()
def insert_Task(name):
name = Checkbutton(root, text=name, command= lambda: del_task(name))
name.pack()
def del_task(name):
name.destroy()
insert_Entry = Entry(root)
insert_Button = Button(root, text="Ok", command=lambda: insert_Task(insert_Entry.get()))
insert_Entry.pack()
insert_Button.pack()
root.mainloop()
The only way this should work is when name is passed into text, it is insert_Entry.get() and when the function is called it is the Checkbutton object.
Can someone explain to me if this is the case?
lambdas are used to create anonymous functions. The code:
command=lambda: insert_Task(insert_Entry.get())
Can also be written as:
def click_next(): #=== any name
insert_Task(insert_Entry.get())
insert_Button=Button(....,command = click_next)
Why do we use lambda to pass arguments?
We need to pass the reference of the function, i.e without providing a (). Or else, the function is executed right away and the returned value is set as the command.
When you click on the button, insert_Entry.get() returns all the text which is entered in insert_Entry. This is passed as the argument in insert_Task where a Check button is created with that name.
Similarly:
name = Checkbutton(root, text=name, command= lambda: del_task(name))
in this, a reference of the Checkbutton is passed as an argument to del_task so that on clicking on it, the method in invoked and the selected check button is destroyed
I'm trying to create new entry boxes when the "ADD entry" is used for my program. I do realize that the 'pack codes' works when I run it individually, but when I combine with existing program which is in grid(), the window is not showing when I run my program.
I also understand that we should not to use both .pack() when I have other things using .grid() in the same program. Hence, my question is, how do I create new entry boxes in grid.
I have tried finding elsewhere but they all suggested pack. For instance: I have looked here here, etc etc, to name a few; but couldn't find anything similar to mine. I would like to add entry boxes below the current entry boxes which is at row 3.
I'm kind of new to Python; (am using Python 2.7 and tkinter module in this program. Thank you very much for the help!
My simplified error codes are as follows:
from Tkinter import *
import tkFileDialog
import tkMessageBox
import Tkinter
import os
class Window:
def __init__(self, master):
self.filename3=""
csvfile=Label(root, text="NUMBERS").grid(row=3, column=0)
bar=Entry(master).grid(row=3, column=3)
self.entryText3 = StringVar()
self.bar = Entry(root, textvariable=self.entryText3).grid(row=3, column=3)
#BUTTONS
self.cbutton= Button(root, text="OK", command=self.process_csv)
self.cbutton.grid(row=15, column=6, sticky = W + E)
####PROBLEM FROM HERE#####
all_entries = []
addboxButton = Button(root, text='ADD', fg="BLUE", command=self.addBox)
addboxButton.pack()
#I have also tried replacing the last 2 lines with the following 2 lines instead but to no avail:
#self.addboxButton = Button(root, text='ADD THA-ID', fg="BLUE", command=self.addBox)
#self.addboxButton.grid(row=3, column=6)
frame_for_boxes = Frame(root)
frame_for_boxes.pack()
def addBox(self):
print "ADD"
next_row = len(all_entries)
lab = Label(frame_for_boxes, text=str(next_row+1))
lab.grid(row=next_row, column=0)
ent = Entry(frame_for_boxes)
ent.grid(row=next_row, column=0)
all_entries.append( ent )
def process_csv(self):
#own program here
print "program"
root = Tk()
window=Window(root)
root.mainloop()
There are few issues with your program other than the one you stated:
Inside the initializer (__init__()) you attached the widgets to root which is not defined within the scope of your Window class. The reasonable way to fix this issue is when you use an instance of Tk(), id est root id est master in Window class, make it as an instance variable. This means the first thing you have to do in the inititializer is this : self.master = master. This will result in you having to replace all root occurrences within __init__() by self.master
The second issue to fix is the one you specified in your question's title: you can not mix the grid() and pack() layout managers for the same widget container. You have to decide which one. Since you placed most of the widgets using grid(), I suggest you to get rid of pack(). This means:
addboxButton.pack() becomes, for example, addboxButton.grid(row=0, column=1)
frame_for_boxes.pack() becomes, for example, frame_for_boxes.grid(row=0, column=0)
The previous list item fixes the problem but it will make you discover other issues within your program which are related:
NameError: global name 'all_entries' is not defined
NameError: global name 'frame_for_boxes' is not defined
This is because those widget variables are not reachable within the scope of addBox() function. To resolve this issue, you have to make those 2 elements as instance variables. This means:
all_entries = [] becomes self.all_entries = []
frame_for_boxes = Frame(root) becomes self.frame_for_boxes = Frame(self.master) (remember we replaced root by self.master in 1.)
The consequence of this error fixing is that you have to use all over inside your program:
self.all_entries instead all_entries
self.frame_for_boxes instead of frame_for_boxes
For scalability reasons, I think you will have at least to make the rest of widgets as instance variables (i.d. prefix them with the self keyword)
As your real project is more complicated than what you show in this MCVE, I encourage you to adopt the SaYa idiom when creating and placing widget elements. This means you will need to replace:
csvfile=Label(root, text="NUMBERS").grid(row=3, column=0)
by
self.csvfile = Label(self.master, text="NUMBERS")
self.csvfile.grid(row=3, column=0)
To avoid unexpected bugs in your program, you must do the same for the remaining widgets you declared in the inititialzer.
There are also other things I would like to mention, but most of them are available on PEP8
What you have to do it to create a command which creates the entries and stores the new entries inside of a variable.
In my case, I use Entry_i and store in Entries but you can use self.Entries to make communication easier. (python 3.5)
def Make_Entry(self, root, Entries, x, y):
Entry_i = Entry(root, bd = 5)
Entry_i.grid(row = x, column = y, sticky = W+E+N+S)
Entries.append(Entry_i)
return(Entries, x+1, y+1)