Strange lambda construct used in tkinter - python

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

Related

My second StringVar fails to show text, shows blank

I was writing a pixel editor in Tkinter, to practice Tkinter and GUI programming. And I was thinking to add a "bottom frame" to show informations like the current tool, the canvas size, etc. But for some reason, the second defined StringVar doesn't seems to work, while the first one works just fine. By this, I mean the code runs just fine but the second StringVar doesn't show anything.
Here is the code, for the bottom frame so far:
# Bottom frame
ttk.Style().configure('Interface.TFrame', background='#dbdbdb')
bottomframe = ttk.Frame(root, style='Interface.TFrame')
bottomframe.grid(column=0, row=2, sticky=(N, S, W, E), pady=4)
# An indicator that shows the current selected tool.
toolname = StringVar()
toolname.set('paint tool')
tool_label = ttk.Label(bottomframe, textvariable=toolname, width=11, background='#dbdbdb', anchor='center')
tool_label.grid(column=0, row=0, sticky=(W, E), padx=2)
# A thin separator.
ttk.Separator(bottomframe, orient=VERTICAL).grid(column=1, row=0, sticky=(N, S, W, E))
# An indicator that shows the canvas size.
cvsize = StringVar()
cvsize.set('50x50 px')
cv_size_label = ttk.Label(bottomframe, textvariable=cvsize, width=11, background='#dbdbdb', anchor='center')
cv_size_label.grid(column=2, row=0, sticky=W, padx=2)
So, why it's not working? The first and the second indicator look nearly same (except the bind operation) and the second one still fails. I also tried removing the first, but it also failed.
I have no idea how can I fix it. I think, I am either missing something and using the StringVar wrong, or there is something in my code that causes this behavior.
So, how can I fix it? And also, why it's happening?
EDIT: Removed the function definiton part. It wasn't really part of the question.
So, I finally understood the reason behind this behavior, thanks to #BryanOakley. Python was removing those unusued variables to free up memory. Because even though they are used in tkinter window, it doesn't really matter for Python, since the mainloop() is what organizing the window. So, it is necessary to save a reference of the variable somewhere, to prevent Python from removing it. And the easiest way of doing this, is saving the variable with self. Which won't get removed even after the class definiton ends.

is it possible to make mouse over function for all button? (in only one function)

i have a problem with mouse over function
this is an example (not the problem):
def on_enter(e):
navi_frame.place(x=0, y=0)
def on_leave(e):
navi_frame.place(x=-200, y=0)
#navigation frame on left side
navi_frame = Frame(root, bg="black", width=250, height=1200)
navi_frame.place(x=0, y=0)
navi_frame.bind("<Enter>", on_enter)
navi_frame.bind("<Leave>", on_leave)
this works well, but i have a lot of buttons. my problem is that i write for each button (or frame) a new function. i tried different things to make only ONE function for all buttons... but all things with if statments etc. don't work (which i tried). i dont find any guide for this, so i want to ask you guys.. . or is it impossible and i need to write for each button a new function?
You Can Do it by Making A List of All Buttons and Then using for loop . As Given Below
b=[Button(r, text=x) for x in range(10)]
And then
for x in range(10):
b[x].bind("<Button>" , lambda event,i=x:fun(i))
Where fun is a Function taking integer as input
def fun(ButtonNumber):
print(ButtonNumber)

I have created a Button but can't find which command to use to change it

I have already created a Button using this code:
btnLuxury=Button(f1,padx=16,pady=8,bd=16, fg="black",font=('arial', 16,'bold'),width=10,
text="Luxury", bg="powder blue", command = Luxury).grid(row=8,column=3)
but when I click on it, it does nothing. Now I want it to display the amount 8000 in the text box of total amount. What do I type after def?
The problem is either in your Luxury() function that wasn't provided, or the setup of your btnLuxury variable. A better approach would be:
btnLuxury=Button(f1,padx=16,pady=8,bd=16, fg="black",font=('arial', 16,'bold'),width=10, text="Luxury", bg="powder blue", command=Luxury)
btnLuxury.grid(row=8,column=3)
Where the creation of your Button and the gridding of it are separate. Otherwise the .grid() method is called (which returns None) and the result (again None) is assigned to the value btnLuxury then later when you try to alter the text of the widget or whatever, you will basically be calling None.configure() whereas with my code above you would be calling Button.configure() instead

Python Tkinter - Passing values with a button

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.

How can I get TK button commands to take in a parameter with a variable (Python)

This has stumped me for over a week. As the title asks, how can I get TK button commands to take in a parameter with a variable?
Here is the exact code I'm using:
i=0
# Make a Staff list button
staffButton = Button(masterFrame,
text='Staff List',
width=20,
justify=LEFT,
#command=lambda:self.openTabHere(isLeft,STAFF_LIST_TAB))
command=lambda:self.openTabHere(isLeft,i))
staffButton.grid(column=0, row=1)
# Make a course list button
courseButton = Button(masterFrame,
text='Course List',
width=20,
justify=LEFT,
#command=lambda:self.openTabHere(isLeft,COURSE_LIST_TAB))
command=lambda:self.openTabHere(isLeft,i))
courseButton.grid(column=0, row=0)
i=1
Note that if I use the commented (hardcoded) command, it works as intended. However, if I use the code not commented, with the variable i, both buttons end up with the command for i=1.
Is it that the command gets the variable i at runtime? If so, or for some other reason, what can I do to accomplish what I'm trying to do?
This is because I do something similar for every staff member; a for loop intending to have buttons that open up a tab with a staff ID that is in the parameter as a variable that can't be hardcoded.
Thanks ahead of time.
You need to bind the value of i at the time you create the widget:
staffButton = Button(..., command=lambda btn=i:self.openTabHere(isLeft,btn))
You probably need to do the same thing for isLeft, unless that's a static value.

Categories

Resources