Below is some code that I'm testing with. In this code, I am able to create a window and have a Label on top and a Entry field on bottom. When I type in that entry field, I can dynamically change what's in the label. Now, I have included a function that is trying to evaluate a variable assigned to "tex", by storing what is predefined in the Entry widget. Which is "cat". This is picked up by:
tex = e.get()
I understand that get() is not changing dynamically as I change the text in the entry widget. So it cannot change to "dog" when I change the string in the entry widget. Is this possible? Here is the code:
from Tkinter import *
import time
root = Tk()
def change():
if tex == ("cat"):
time.sleep(0.5)
pass
else:
time.sleep(0.5)
e.delete(0, END)
e.insert(0, "dog")
v = StringVar()
e = Entry(root, textvariable=v)
e.insert(0, "cat")
e.pack(side=BOTTOM)
tex = e.get() #When text is defined with get(), it does not change
#dynamically with the entry widget
l = Label(root, textvariable=v)
l.pack(side=TOP)
change()
root.mainloop()
Any help would be appreciated.
To answer your specific question, no, there is no way for tex to magically keep updated when the entry widget changes. That feature is exactly why the textvariable attribute exists -- it causes the variable to always be updated with the value in the entry widget. If you need the data in another variable, you will have to call the .get() method.
That being said, you can set a trace on the variable, or a binding on the entry widget, and have it call code that can update tex to whatever you want when the entry widget changes.
For example, the following code shows how to have callback called whenever the value in the entry widget changes:
def callback(*args):
global tex
tex = e.get()
v.trace("w", callback)
For more information about what arguments are passed to the callback, see What are the arguments to Tkinter variable trace method callbacks?
All that being said, you have a couple of critical flaws in your code. First, you are creating the StringVar incorrectly. It needs to be v = StringVar() (note the trailing ()).
Also, you should never call sleep in the main thread of a GUI program. Read up on the after method if you want to execute some code after some time has elapsed.
Related
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
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?
this is my first project using Tkinter so please excuse me if the question is very simple to solve.
Depending on what option the user chooses from a dropdown, I call a function that creates and places certain widgets (e.g. an entry) on a frame. Then, when another button is pushed I want to access the text inside this entry. However, this seems to be giving me errors (saying that the widget is undefined) because I want to access a widget which I create when a function is called.
An obvious solution I see is to create all possible widgets I want to use outside the function, and only place them when the function is called. This seems quite sloppy and creates many more issues. Is there another fix?
Thanks in advance!
This is the function where I create and place the widgets on the frame.
def loadBook():
print("book is loaded")
#Authors
labelAuth1 = tk.Label(frame, text="Author 1 Name:")
entryAuth1 = tk.Entry(frame)
labelAuth1.place(relwidth=0.23, relheight=0.08, rely=0.1)
entryAuth1.place(relheight=0.08, relwidth=0.18, relx=0.3, rely=0.1)
This is a snippet of a function which uses input from the entry widget I created above:
def isBook():
if len(entryAuthSur1.get())==0:
pass
else:
bookString = ""
bookString += entryAuthSur1.get()
When the second function executes, I get a runtime error that entryAuthSur1 is not defined.
All variables inside functions are local. That means that it is deleted after the function call ends. As your variable (entryAuth1) wasn't global so it only existed inside the function and was deleted when the loadBook function ended. This is the working code:
import tkinter as tk
# Making a window for the widgets
root = tk.Tk()
def loadBook():
global entryAuth1 # make the entry global so all functions can access it
print("book is loaded")
#Authors
labelAuth1 = tk.Label(root, text="Author 1 Name:")
entryAuth1 = tk.Entry(root)
# I will check if the user presses the enter key to run the second function
entryAuth1.bind("<Return>", lambda e: isBook())
labelAuth1.pack()
entryAuth1.pack()
def isBook():
global entryAuth1 # make the entry global so all functions can access it
# Here you had `entryAuthSur1` but I guess it is the same as `entryAuth1`
if len(entryAuth1.get())==0:
pass
else:
bookString = ""
bookString += entryAuth1.get()
print(bookString) # I am going to print the result to the screen
# Call the first function
loadBook()
root.mainloop()
I'm using TKinter (I'm new with GUI tools), and I would like to know if it is possible to add (or activate) a entry with base on the answer of a option menu. Below is a part of the code
from Tkinter import *
win=Tk()
Label(win, text="Is This a Data Cube?",font='20').grid(row=14, column=0,sticky=W)
DataCubeValue = StringVar(win)
DataCubeValue.set("False")
DataCube = OptionMenu(win,DataCubeValue,"True","False")
DataCube.grid(row=15, column=0,sticky=W)
If the answer is True is choosen I would like to display this:
Label(win, text="X and Y values (x,y)",font='20').grid(row=14, column=1,sticky=W)
XYValue = StringVar(win)
XYValue.set("10,7")
XY = Entry(win,textvariable=XYValue)
XY.grid(row=15, column=1,sticky=W)
A central idea of GUI programming is to register code to be executed in reaction of user actions. Such code is usually named callback (the toolkit call it back depending on user actions on the interface).
You can bind to DataCubeValue changes with the following line. callback method (to be defined before) will be cause each time the value of DataCubeValue change.
DataCubeValue.trace("w", callback)
In the callback method, you can either choose to place the block of code with Label and Entry instantiation, but think that callback will be called every time the user change the OptionMenu value. You could either deactivate the OptionMenu once the user used it, but I would advise to instantiate your widgets in the initial run, and just display or hide them from the callback.
def callback(*args):
if DataCubeValue.get() == "True":
label.grid(row=14, column=1,sticky=W)
XY.grid(row=15, column=1,sticky=W)
else:
label.grid_forget()
XY.grid_forget()
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.