Keep unique variable in for loop widget command - python

Im adding/removing strings from an optionmenu widget and i've learned that you have to run a command or function when a string is added that sets the widget variable to that string. This is done automatically for strings provided when the widget is originally created.
from tkinter import *
def _print(var, string):
print(string)
var.set(string)
lst = ['hello', 'bob', 'testing']
main = Tk()
var = StringVar()
options = OptionMenu(main, var, 'option1')
options.grid()
for string in lst:
options['menu'].add_command(label=string, command=lambda: _print(var, string))
main.mainloop()
As you click each option in the menu it should print the string on the widget so you know you have it selected. The problem is that the for loop is setting all of the commands to use the same variable. It looks like its just not keeping a unique variable for each line that is run. I've tried lambda event, i=string: _print(var, i) but even if I set the _print function to receive an event lambda always says its missing an event. Maybe i'm trying to do the i=string part wrong or it cant be done this way.
How can I keep the variable "string" unique for each add_command line that is run?

Related

Hi , How can I change a string number from Entry of tkinter into int number?

Hi i'm a beginner in python and I really got int trouble with some methods, I wanna give some number from Entry of tkinter class and show them with a chart,
but the thing is that I cant get int number:
so the chart wont work [here is the picture of my code , I get some bumber from entry but i cant make them integer number]
1: https://i.stack.imgur.com/2Vuvn.jpg
2: https://i.stack.imgur.com/Pa23V.jpg
Welcome. I'm posting a complete, I think, answer to this question but there are a couple of etiquette things you should know:
Please don't post screenshots of your code. Copy and paste into the editor.
Please post just enough code to show your problem, but which is complete enough that we can just copy it into our own editors / IDEs and run without a lot of modification.
The previous commenters are correct that this question has probably been answered a hundred times, so please try to search through previous answers before posting your question.
Having said that, I have not answered this question before, so here's my rendition. I know you're a beginner so I've tried to keep it as simple as possible, but you're also tackling TKinter so I've not made it overly simplistic.
import tkinter as tk
def main():
global entryVar, lableVar
#create a tkinter window:
rootWin = tk.Tk() #creates a root window
rootWin.title('Entry Test') #shows text on the title bar
rootWin.geometry('500x200') #sets the displayable size of the window
#we'll need these variables and they MUST be tk.StringVar()
entryVar = tk.StringVar() #variable to hold the entry value
lableVar = tk.StringVar() #variable to hold the lable value
#create an entry widget:
entry = tk.Entry(
rootWin,
width = 5,
textvariable = entryVar
)
entry.pack(expand=1)
entry.bind('<Return>', getEntryValue) #bind enter key to widget
entry.bind('<KP_Enter>', getEntryValue, add='+') #bind the other enter key to widget
#create a lable widget
lable = tk.Label(
rootWin,
textvariable = lableVar
)
lable.pack(expand=1)
lableVar.set("This is where the lable is.")
entry.focus_set() #set focus on the entry widget for convenience
rootWin.mainloop()
def getEntryValue(event):
global entryVar, lableVar
x = entryVar.get() #get the value from Entry
x = int(x) #change it to an int
lableVar.set(x) #set the lable variable
entryVar.set("") #clear the entry variable
if __name__ == "__main__":
main()
So, what's going on here is that we make a window in the usual way. I've created both an Entry() widget to get some input, and a Label() widget to show whatever has been input. I've broken the Entry() and Label() declarations up over multiple lines just to make them easier to read.
You can attach variables to many TKinter widgets to that you can .get() and .set() their values more easily, but they almost always need to be TKinter variable types such as StringVar() or IntVar(). I've created two such variables, one for the Entry() widget and another for the Label() widget.
I've also added "bindings" to the Entry() widget to both show how that works and to make data entry a bit more convenient. I don't know if you have a separate number pad on your computer keyboard so I've bound both the main <enter> key as well as the number pad's <enter> key. When you hit either one of those keys, the Entry() widget will call the getEntryValue() function which does the work of getting the value and displaying it on the window.
For convenience, entry.focus_set() immediately puts the focus on the Entry() widget, then the TKinter window enters the .mainloop() to do its stuff.
The getEntryValue() function is called by the events which we set on the Entry() widget. I broke it down into more lines than necessary to illustrate what needs to happen. First we retrieve the value of the Entry() widget through its variable, entryVar. You do that using entryVar's .get() method: x = entryVar.get(). That returns a string value which you will have to convert to an integer using the normal int() function available in Python. For this purposes of this demonstration I've chosen to display that value to a Label() widget which I've placed in the window, so I use the Label() widget's variable lableVar: lableVar.set(x). You don't have to convert the integer back into a string before doing this.
I then clear out the entryVar variable so that there isn't anything left in the Entry() widget to get in the way of our next entry.
I've used entryVar and lableVar as globals just to simplify the example.
And that's how you do it.
I guess the problem is here:
a=str(e3.get())
Try something like this:
a=int(e3.get())
Since what you want is an integer

Adding and updating new widget in tkinter in runtime

I am trying to build a GUI creator using Python and Tkinter, but ran into a problem.
My problem is How to add\update widgets in runtime?
for example:
I have created the main window.
In that main window, I have created a frame name w_frame which contains a bunch of widget.
Based on my input in the Text or Entry widget beside the w_frame, I want to update a particular widget.
Lets say w_frame contains a Entry widget, radio button, button and label all available with the basic or main attributes need to display it.
Now I want to change the background color of label.
In short I want to write the code label_name.property_name=value or for example a_label.bg=red in the text widget and as soon as I press apply button, the widget should change.
I have searched on web, but not able to find the required solution. Also tried using How can i update a certain widget in tkinter, but that does not work depending on my input.
from tkinter import *
root=Tk()
w_frame=Frame()
w_frame.pack()
def update_Frame():
a=u_text_wid.get("1.0",END)
b.config(a)
root.update()
def add_wid_in_frame():
global a,b
a=Button(w_frame,text='heelo')
a.pack()
b=Label(w_frame,text='heelo')
b.pack()
u_text_wid=Text()
u_text_wid.pack()
button1=Button(text="add",command=add_wid_in_frame)
button1.pack()
button1=Button(text="update",command=update_Frame)
button1.pack()
root.mainloop()
this results me in an error
unknown option "-bg="red"
Note:
I want to update the widget based on the property value provided by the user, so it wont be hard-code into the script.
You are getting the error because every thing you retrieve from Text widget is a string and you cannot directly pass an string to .config method, you need a keyword and then you can assign value which can be string.
According to your question and the comments on the question, what i have figured out is:
You want to run lable.config(bg='red') from the Text widget.
You want to change the property of specific widget.
Here's what you can do:
To run Tkinter code form Text widget, you can use:
getattr method
eval method
Just to change property of widget:
def update_Frame():
global bcd
a = u_text_wid.get("1.0", "end-1c")
b=a.split(",")
c=[tuple(i.split("=")) if "=" in i else i for i in b]
d=dict(i for i in c)
for key,value in d.items():
bcd[key]=value
We can use string to change property only in this format widget_name[key]=value.
Some Useful Links:
Eval()
Getattr()
For your case, you can use ast.literal_eval() to convert a JSON string to dictionary and use the dictionary in .config():
from ast import literal_eval
...
def update_Frame():
a = u_text_wid.get("1.0", "end-1c") # don't include ending newline
cnf = literal_eval(a) # convert JSON string to dictionary
b.config(cnf)
Example input of the JSON string:
{"fg":"yellow", "bg":"red"}
Note that you can also use json module to convert the JSON string as well.

Tkinter fails to pass Entry data between two functions

When I run the following code, I receive the following error: NameError: name 'barE' is not defined.
Does Tkinter's Entry work from one function to another? I have a global window and frame in this program and it passes the user's input without error using the same syntax as below.
def newSearchForm():
window2=Tk()
window2.geometry("650x400")
frame = Frame(window2)
frame.pack(side="top", expand=True, fill="both")
barcode=Label(frame,text="Please Enter The Barcode", font='time 15')
barcode.place(x=10,y=90)
barE=Entry(frame)
barE.place(x=250,y=90)
isbn=Label(frame,text="Please Enter The ISBN", font='time 15')
isbn.place(x=10,y=130)
isbE=Entry(frame)
isbE.place(x=250,y=130)
repeatSearchButton=Button(frame,text="Enter", command=newSearch,width=12,bg='gray')
repeatSearchButton.place(x=150,y=170)
window.mainloop()
def newSearch():
uB = barE.get()
uI = isbE.get()
carlSearch(uB, uI)
itemTitle=workspace.find_element_by_xpath('//*[#id="mainContent"]/div[2]/div[2]/div[2]/div[1]/div[1]/div').text
ingramSearch()
fantasticFictionSearch(itemTitle)
outputMetadata()
I tried using the lambda command to explicitly pass the variables and that didn't work.
I tried using anexising window and that didn't work, so I destroyed it and created a new one.
I would suggest you to use text variable. You can create a text variable by StringVar and assign it in the entry widget.
For more details on why to use text variable see Should I use Entry's .get() or its textvariable's for Tkinter in Python?
Usage:
barE_var=StringVar()
barE=Entry(frame,textvariable=barE_var)
barE.place(x=250,y=90)
To get value use barE_var.get().
Does Tkinter's Entry work from one function to another?
It does work, but have to use global keyword to access them.
def newSearch():
global barE_var

Checking if the user presses 'Return' while selected in an Entry box Tkinter

I'm using Tkinter to create a GUI for a simple geometry calculator I'm creating.
Basically, what I have is an Entry box. What I want is for the program/GUI/system to detect when the user of the program hits the 'Enter' or 'return' key WHILE they are in the Entry box. When this is detected, I want the contents of the Entry box to be appended to a list I have defined earlier. I also want a simple label to be created on the GUI that displays the contents of the list (including the appended item(s)). Note that the list begins with nothing in it.
Here is my code so far:
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint).grid(row=0, column=0)
app.bind('<Return>', list_add)
mainloop()
I don't really know the proper way to check for 'Return' and then use it in an if statement.
I hope you understand what I'm trying to get help with, and I've looked all around for an explanation that I could understand with no success.
Instead of binding with the app just bind it with the Entry widget object,i.e,e1
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
print ("hello")
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint)
e1.grid(row=0, column=0)#use grid in next line,else it would return None
e1.bind('<Return>', list_add)# bind Entry
mainloop()
The solution is to set the binding on the widget itself. That way, the binding will only apply while focus is on that widget. And since you're binding on a specific key, you don't need to check for the value later. You know the user pressed return, because that's the only thing that will cause the binding to fire.
...
e1.bind('<Return>', list_add)
...
You have another problem in that your list_add function needs to call the get method of the variable rather than accessing the variable directly. However, since you aren't using any of the special features of a StringVar, you really don't need it -- it's just one more thing you have to manage.
Here's how to do it without the StringVar:
def list_add(event):
PointLit.append(e1.get())
...
e1 = Entry(app)
e1.grid(row=0, column=0)
e1.bind('<Return>', list_add)
Note that you need to create the widget and lay out the widget in two steps. Doing it the way you did it (e1=Entry(...).grid(...) will cause e1 to be None since that is what .grid(...) returns.

How to detect when an OptionMenu or Checkbutton change?

My tkinter application has several controls, and I'd like to know when any changes occur to them so that I can update other parts of the application.
Is there anything that I can do short of writing an updater function, and looping at the end with:
root.after(0, updaterfunction)
This method has worked in the past but I'm afraid that it might be expensive if there are many things to check on.
Even if I did use this method, could I save resources by only updating items with changed variables? If so, please share how, as I'm not sure how to detect specific changes outside of the update function.
Many tkinter controls can be associated with a variable. For those you can put a trace on the variable so that some function gets called whenever the variable changes.
Example:
In the following example the callback will be called whenever the variable changes, regardless of how it is changed.
def callback(*args):
print(f"the variable has changed to '{var.get()}'")
root = tk.Tk()
var = tk.StringVar(value="one")
var.trace("w", callback)
For more information about the arguments that are passed to the callback see this answer
To have an event fired when a selection is made set the command option for OptionMenu
ex.
def OptionMenu_SelectionEvent(event): # I'm not sure on the arguments here, it works though
## do something
pass
var = StringVar()
var.set("one")
options = ["one", "two", "three"]
OptionMenu(frame, var, *(options), command = OptionMenu_SelectionEvent).pack()
If you are using a Tkinter Variable class like StringVar() for storing the variables in your Tkinter OptionMenu or Checkbutton, you can use its trace() method.
trace(), basically, monitors the variable when it is read from or written to.
The trace() method takes 2 arguments - mode and function callback.
trace(mode, callback)
The mode argument is one of “r” (call observer when variable is read by someone), “w” (call when variable is written by someone), or “u” (undefine; call when the variable is deleted).
The callback argument is the call you want to make to the function when the variable is changed.
This is how it is used -
def callback(*args):
print("variable changed!")
var = StringVar()
var.trace("w", callback)
var.set("hello")
Source : https://dafarry.github.io/tkinterbook/variable.htm
This will print the dropdown selection to the console. but my suggestion is to avoid console in GUI based applications. create a text indicator and print output to it
use the function in below code
from tkinter import *
tk = Tk()
def OptionMenu_SelectionEvent(event):
print(var.get())
pass
var = StringVar(); var.set("one")
options = ["one", "two", "three"]
OptionMenu(tk, var, *(options), command = OptionMenu_SelectionEvent).pack()
tk.mainloop()

Categories

Resources