Entry data manipulation difficulties [duplicate] - python

I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?

It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.

You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.

A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()

*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.

you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)

Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()

Related

Tkinter - Python, how do I cause a button click to assign a value to a variable?

Using Tkinter and Python. Already created a window for the buttons to be placed on. I want there to be four buttons to appear, and I want to be able to click one of the four buttons, and be able for it to set the selection variable = "whatever I clicked", so that I can then use this variable later to call an API. When I run the program and click on the "General knowledge" button and print the selection, it does correctly print "General knowledge", but then when I try to return this selection variable it just doesn't work and I don't know why.
def select1():
selection = "General Knowledge"
print(selection)
def select2():
selection = "Science"
def select3():
selection = "Entertainment"
def select4():
selection = "Miscellaneous"
button1 = tk.Button(text = "General Knowledge", command = select1)
button1.place(x=100, y=100)
button2 = tk.Button(text = "Science", command = select2)
button2.place(x=100, y=140)
button3 = tk.Button(text = "Entertainment", command = select3)
button3.place(x=100, y=180)
button4 = tk.Button(text = "Miscellaneous", command = select4)
button4.place(x=100, y=220)
There are several ways to accomplish your goal.
One way is to write a single function that will take a value to assign to your variable. This way you can have as many buttons as you like and only a single function.
Not if you are using functions you have to either pass the variable to the function or let the function know it is in the global namespace.
import tkinter as tk
root = tk.Tk()
selection = ''
def assign_value(value):
global selection
selection = value
lbl["text"] = value
print(selection)
lbl = tk.Label(root, text='Selection Goes Here')
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: assign_value("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: assign_value("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: assign_value("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: assign_value("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
Or you can assign the value directly from the button.
import tkinter as tk
root = tk.Tk()
selection = tk.StringVar()
selection.set('Selection Goes Here')
lbl = tk.Label(root, textvariable=selection)
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: selection.set("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: selection.set("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: selection.set("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: selection.set("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
I am sure if I spent more time on this I could think up something else but the idea is basically write your code in a more DRY (Don't Repeat Yourself) fashion and make sure you are assigning the value to the variable in the global namespace or else it will not work as you expect.

Python Tkinter Entry.get() gives previous input

I am working on a relatively large project, but have managed to recreate my problem in just a few lines:
import tkinter as tk
root = tk.Tk()
root.geometry('200x200')
def doStuff():
pass
sv = tk.StringVar()
def callback():
print(E.get())
doStuff()
return True
E = tk.Entry(root, bg="white", fg="black", width=24, textvariable=sv, validate="key",validatecommand=callback)
E.grid(row=0, column=0, padx=30, pady=5, sticky=tk.E)
root.mainloop()
The desired output would be that every time the user changes the entry in this Entrywidget, a function is called.
This works just fine, but using E.get() returns the 'previous' entry, for example:
-entry is 'boo'
-E.get() is 'bo'
Python seems to run Callback() before the Entry Widget has been changed.
Validation by design happens before the text has been inserted or deleted. For validation to work, it must be able to prevent the data from being changed.
If you aren't doing validation, but instead just want to call a function when the value changes, the best way to do that is to put a trace on the associated variable.
def callback(*args):
print(E.get())
doStuff()
return True
sv = tk.StringVar()
sv.trace_add("write", callback)

I found a function a bit of code on here that works but I don't understand why it works

The code is below from this post:
Why is Tkinter Entry's get function returning nothing?
The argument in the return_entry is 'en' and when I deleted it out it says a positional argument is missing. What is the def return_entry('en') mean and why does it only work with it.
Why cant i just use:
def return_entry():
The en argument makes no sense to me...
from tkinter import *
master = Tk()
def return_entry(en):
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
Error:
TypeError: return_entry() takes 0 positional arguments but 1 was given
Only throws an error when I remove en and hit enter after I enter input in the entry box.
bind expects function which can get argument to send event to this function - and it will run it as return_entry(event). And this is why you can't use function without argument.
You can even use this event to get access to entry - so you can assing the same function to different entries and ifunction will get text from correct entry
def return_entry(event):
content = event.widget.get()
print(content)
Sometimes we may want to use the same function with command= which doesn't send event to function and then we can use event=None but then we can't use event inside function
def return_entry(event=None):
content = entry.get()
print(content)
entry.bind('<Return>', return_entry)
tk.Button(..., command=return_entry)
Working examples:
Function binded to two entries:
import tkinter as tk
def return_entry(event):
content = event.widget.get()
print(content)
root = tk.Tk()
entry1 = tk.Entry(root)
entry1.pack()
entry1.bind('<Return>', return_entry)
entry2 = tk.Entry(root)
entry2.pack()
entry2.bind('<Return>', return_entry)
root.mainloop()
Function assigned to Entry and Button
import tkinter as tk
def return_entry(event=None):
content = entry.get()
print(content)
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
entry.bind('<Return>', return_entry)
button = tk.Button(root, text='OK', command=return_entry)
button.pack()
root.mainloop()

Tkinter Entry widget requires two events to update

I've been trying to develop a small gui to calculate some totals with weighting etc. While trying to get a total to update real-time with a changing entry, I noticed it took two events to update; This is a simplified version of my code that shows the problem:
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
entry=Entry(frame)
entry.pack()
label=Label(frame,text="entry:")
label.pack()
def updatelabel(event):
label=Label(frame,text="entry:"+entry.get())
label.pack()
print "called"
entry.bind("<Key>", updatelabel)
root.mainloop()
When you input into the field the function calls, but does not update to what was typed until the next character is typed. How would I go about getting the label to update to what is in the field at the time?
You don't really need to explicitly process events and use callback functions to accomplish what you want. In other words it's possible to get Tkinter to do it for you automatically using a StringVar().
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
entry_var = StringVar()
entry_var.set('')
entry = Entry(frame, textvariable=entry_var)
entry.pack()
label = Label(frame, text='entry: ')
label.pack(side=LEFT)
contents = Label(frame, textvariable=entry_var)
contents.pack(side=LEFT)
entry.focus_set() # force initial keyboard focus to be on entry widget
root.mainloop()
Instead of using entry.bind("<Key>", update label), I used the root window instead: root.bind("<Key>", update label). This did the trick, however it is important to realize that the function updatelabel() will be called every time a key is pressed in your tkinter window. This could cause some problems if you have more than one entry box updating labels.
Here is the code I wrote with a few modifications:
from Tkinter import *
root=Tk()
frame=Frame(root)
frame.pack()
update_label = StringVar() # Made a StringVar so you don't get new labels every time a key is pressed.
update_label.set("entry:")
entry=Entry(frame)
entry.pack()
label=Label(frame,textvariable=update_label) # Used textvariable= instead of text=
label.pack()
def updatelabel(event):
update_label.set("entry:" + entry.get()) # Setting the variable used in textvariable=
print "called"
root.bind("<Key>", updatelabel) # Changed entry.bind to root.bind
root.mainloop()
No it doesn't require two entries to be called, it is called on the first entry. The key bindings are on the Entry widgets to avoid the problems that a binding to the root will create if you have more than one entry widget.
import tkinter as tk
class SmallApp(tk.Frame):
def __init__(self, master = None):
tk.Frame.__init__(self, master)
self.master = master
self.pack()
self.entry = tk.Entry(self)
self.entry.pack()
self.var = "entry:"
self.label = tk.Label(text = self.var)
self.label.pack()
self.entry.bind("<Key>", self.updatelabel)
def updatelabel(self, event):
self.var += event.char
self.label.configure(text=self.var)
root = tk.Tk()
app = SmallApp(root)
app.mainloop()

.get() not giving a value [duplicate]

I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()

Categories