This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 7 years ago.
class FCMenu:
def __init__(self,master):
frame=Frame(master)
frame.pack()
Label(frame, text="What is the number?").grid(row=0)
self.num = IntVar()
self.entry = Entry(frame,textvariable=self.num).grid(row=1)
button = Button(frame, text="Factorize", command=self.calc).grid(row=2)
self.resultvar = StringVar()
Label(frame, textvariable=self.resultvar).grid(row=3)
def calc(self):
e = int(self.entry.get())
print(e,self.num.get())
...
I am trying to create a Python GUI with tkinter, as shown above. However, every time I call .get() on the entry or the textvariable, it fails. With the entry itself, it explains that there is no .get() function for NoneType. If I remove that and use only self.num.get(), it prints 0 or 0.0, depending on whether or not I turn it to an integer. If I turn self.num to a StringVar, it prints nothing at all. Simply, I cannot find a way to obtain the input that I want to retrieve.
Made a simplified version of your code, and it prints correctly as the Entry widget is changed. Could be error elsewhere in your code? Or wrong indentation? Here is the code I tested with (this is 2.7 code, but worked with a 3.5 version of the code also):
import Tkinter as tk
class FCMenu:
def __init__(self, master):
frame = tk.Frame(master)
self.num = tk.IntVar()
self.entry = tk.Entry(frame, textvariable=self.num)
self.button = tk.Button(frame, text='Calc', command=self.calc)
frame.pack()
self.entry.pack()
self.button.pack()
def calc(self):
print(self.num.get(), self.entry.get())
root = tk.Tk()
frame = FCMenu(root)
root.mainloop()
It prints from both self.num.get() and self.entry.get(). The first is an Int and the second as String it seems.
Related
This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 2 years ago.
So i am trying to get an text input for my program but tkinter doesn't seem to register it,
and i don't know what i have done wrong
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
My code looks something like this. Everything else is working the self.newWindow(value) is just
a function that creates a new window from the main one
so i said text=e1.get() but i ran the debbuger and it says it is an empty string and i want to pass this text through the function passValue()(a function that passes the value to the controller), i used button.bind() to do that. Is that ok?
I tested it by putting a default value at text like text="My name" and it did pass the value so that should be in order but i don't know why doesn't it get it from the entry box like it should.
I even tried to do e1.insert(0,"some random thing") and text= e1.get() and it did get it so i think there's a problem with the input.
Do i need to use some special kind of input function?
The whole code:
class Gui:
def __init__(self, controller):
self.main = tk.Tk()
self.main.title("DSA Quiz Helper")
self.__controller = controller
def IntFixPostExecute(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.IntfixPostfixWindow(value)
def mainWindow(self):
self.main.geometry("800x500")
# to do scrollbar
lb = tk.Listbox(self.main, width=50, height=30)
lb.insert(1, "Intfix and Postfix Calculator")
lb.insert(2, "Something else")
lb.bind("<Double-Button-1>", self.IntFixPostExecute)
lb.pack()
def IntfixPostfixWindow(self, value):
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
print(text)
def passValue(self, rezultat, value):
returnValue = self.__controller.InfixToPostC(rezultat, value)
rezultat.insert(tk.INSERT, returnValue)
def newWindow(self, msg):
newwind = tk.Toplevel(self.main)
q1 = tk.Frame(newwind)
q1.pack()
newwind.geometry("500x230")
return newwind
def run(self):
self.mainWindow()
self.main.mainloop()
if i set this manually it works. I don't understand why i doesn't work from entrybox input
text = tk.StringVar()
e1 = tk.Entry(window, textvariable=text)
text.set("x+y*2")
text = e1.get()
e1.place(x=0, y=50)
I think i figured it out (correct me if i am wrong). I think there is a problem
with the button because as soon as a newwindow is open, the button automatically clicks itself, when at first in the entry box there is no text written yet(so it sends to the controller with the initial text(which is empty)). The problem is why the button auto-clicks itself( or anyway auto-runs the function passValue) and why after i input the text and click the button again it does nothing(so as i understand it works only one time and auto-runs itself, at first there is no text in entrybox and the button auto-runs itself,therefore passing an empty string
You should use entryname.get() to get the text that is inside that entry instead of declaring stringVar() and making that much more unreadable and hard to comprehend and to work with. But this is my point of view! – Tiago Oliveira 48 mins ago
I think what is happening is that u use the method right after declaring the entry widget wich means u are going to get a "" empty string because that's nothing that was written there, u need to replace on the command parameter with entryname.get() instead of declaring variable = entryname.get() and passing that as parameter wich will always be empty! Hope this helps!
This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 4 years ago.
I am trying to create a programme which gathers experimental data. I have succesfully created a table containing label and entry widgets. However when trying to make the entry widgets functional by gathering entered data, my script fails.
import tkinter as tk
from PIL import ImageTk, Image
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Data Analyser")
tk.Label(self.master, text="Cell Number").grid(row=1, sticky=tk.W)
tk.Label(self.master, text="1").grid(row=2)
tk.Label(self.master, text="1").grid(row=2)
tk.Label(self.master, text="Treatment").grid(row=1, column=2)
Treatment_1 = tk.Entry(self.master).grid(row=2,column=2)
Treatment_2 = tk.Entry(self.master).grid(row=3,column=2)
tk.Button(self.master, text = "Submit", command = self.getInput).grid(row = 14, column = 2)
def getInput(self):
global Treatment_Data
a = Treatment_1.get()
b = Treatment_2.get()
Treatment_Data = [a,b]
root = tk.Tk()
root.geometry("500x450")
app = Window(root)
root.mainloop()
I was hoping the above code would generate a global variable called 'Treatment_Data', but unfortinately I receive the following error message when I click the 'Submit' widget:
Traceback (most recent call last):
File "C:\Users\xxxx\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "<ipython-input-134-2b5d212a0dcf>", line 47, in getInput
a = self.Treatment_1.get()
AttributeError: 'NoneType' object has no attribute 'get'
Any clarification would be greatly appreciated.
You need to use self to make Treatment_1 and Treatment_2 as class variable only then you can access them in the callback function getInput(). Another thing as mentioned in the comment is that you need to separate the two parts - 1. Creating an Entry Widget and 2. placing it in the grid. You should create an Entry widget and store it in Treatment_1. Once it is done, you should use the Treatment_1 variable to place the widget in the desired position in the grid.
import tkinter as tk
from PIL import ImageTk, Image
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Data Analyser")
tk.Label(self.master, text="Cell Number").grid(row=1, sticky=tk.W)
tk.Label(self.master, text="1").grid(row=2)
tk.Label(self.master, text="1").grid(row=2)
tk.Label(self.master, text="Treatment").grid(row=1, column=2)
self.Treatment_1 = tk.Entry(self.master)
self.Treatment_2 = tk.Entry(self.master)
self.Treatment_1.grid(row=2,column=2)
self.Treatment_2.grid(row=3,column=2)
tk.Button(self.master, text = "Submit", command = self.getInput).grid(row = 14, column = 2)
def getInput(self):
global Treatment_Data
a = self.Treatment_1.get()
b = self.Treatment_2.get()
Treatment_Data = [a,b]
print(Treatment_Data)
root = tk.Tk()
root.geometry("500x450")
app = Window(root)
root.mainloop()
I would like to ask if anyone knows how to get out a variable from an Entry in Tkinter to be used in future calculation.
Let us assume that I want to create a prompt where the user needs to place two numbers in the two different Entry widgets.
These numbers are to be used in another script for calculation. How can I retrieve the values from the prompt created in Tkinter?
In my opinion, I would need to create a function with the code bellow and make it return the value from the Tkinter prompt. However, I cannot return the numbers because I'm destroying the root window. How can I get pass this, preferably without global variables.
Best Regards
from tkinter import *
from tkinter import ttk
#Start of window
root=Tk()
#title of the window
root.title('Title of the window')
def get_values():
values=[(),(value2.get())]
return values
# Creates a main frame on the window with the master being the root window
mainframe=ttk.Frame(root, width=500, height=300,borderwidth=5, relief="sunken")
mainframe.grid(sticky=(N, S, E, W))
###############################################################################
#
#
# Label of the first value
label1=ttk.Label(master=mainframe, text='First Value')
label1.grid(column=0,row=0)
# Label of the second value
label2=ttk.Label(master=mainframe, text='Second Value')
label2.grid(column=0,row=1)
###############################################################################
#
#
# Entry of the first value
strvar1 = StringVar()
value1 = ttk.Entry(mainframe, textvariable=strvar1)
value1.grid(column=1,row=0)
# Entry of the second value
strvar2 = StringVar()
value2 = ttk.Entry(mainframe, textvariable=strvar2)
value2.grid(column=1,row=1)
# Creates a simplle button widget on the mainframe
button1 = ttk.Button(mainframe, text='Collect', command=get_values)
button1.grid(column=2,row=1)
# Creates a simplle button widget on the mainframe
button2 = ttk.Button(mainframe, text='Exit', command=root.destroy)
button2.grid(column=2,row=2)
root.mainloop()
You use a class because the class instance and it's variables remain after tkinter exits.https://www.tutorialspoint.com/python/python_classes_objects.htm And you may want to reexamine some of your documentation requirements, i.e. when the statement is
"root.title('Title of the window')", adding the explanation "#title of the window" is just a waste of your time..
""" A simplified example
"""
import sys
if 3 == sys.version_info[0]: ## 3.X is default if dual system
import tkinter as tk ## Python 3.x
else:
import Tkinter as tk ## Python 2.x
class GetEntry():
def __init__(self, master):
self.master=master
self.entry_contents=None
self.e = tk.Entry(master)
self.e.grid(row=0, column=0)
self.e.focus_set()
tk.Button(master, text="get", width=10, bg="yellow",
command=self.callback).grid(row=10, column=0)
def callback(self):
""" get the contents of the Entry and exit
"""
self.entry_contents=self.e.get()
self.master.quit()
master = tk.Tk()
GE=GetEntry(master)
master.mainloop()
print("\n***** after tkinter exits, entered =", GE.entry_contents)
So, I have taken Curly Joe's example and made a function with the his sketch
The final result, for anyone wanting to use this as a template for a input dialog box:
def input_dlg():
import tkinter as tk
from tkinter import ttk
class GetEntry():
def __init__(self, master):
self.master=master
self.master.title('Input Dialog Box')
self.entry_contents=None
## Set point entries
# First point
self.point1 = ttk.Entry(master)
self.point1.grid(row=0, column=1)
self.point1.focus_set()
# Second point
self.point2 = ttk.Entry(master)
self.point2.grid(row=1, column=1)
self.point2.focus_set()
# labels
ttk.Label(text='First Point').grid(row=0, column=0)
ttk.Label(text='Second Point').grid(row=1, column=0)
ttk.Button(master, text="Done", width=10,command=self.callback).grid(row=5, column=2)
def callback(self):
""" get the contents of the Entries and exit the prompt"""
self.entry_contents=[self.point1.get(),self.point2.get()]
self.master.destroy()
master = tk.Tk()
GetPoints=GetEntry(master)
master.mainloop()
Points=GetPoints.entry_contents
return list(Points)
In python, functions are objects, as in get_values is an object.
Objects can have attributes.
Using these two, and the knowledge that we can't really return from a button command, we can instead attach an attribute to an already global object and simply use that as the return value.
Example with button
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def on_button_press(entry):
on_button_press.value = entry.get()
entry.quit()
def main():
root = tk.Tk()
entry = tk.Entry(root)
tk.Button(root, text="Get Value!", command=lambda e = entry : on_button_press(e)).pack()
entry.pack()
tk.mainloop()
return on_button_press.value
if __name__ == '__main__':
val = main()
print(val)
Minimalistic example
Similarly modules are also objects, if you want to avoid occupying global namespace extremely, you can attach a new attribute to the module you're using
See:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
if __name__ == '__main__':
tk.my_value = lambda: [setattr(tk, 'my_value', entry.get()), root.destroy()]
root = tk.Tk()
entry = tk.Entry(root)
root.protocol('WM_DELETE_WINDOW', tk.my_value)
entry.pack()
tk.mainloop()
print(tk.my_value)
This question already has an answer here:
(Python) How to limit an entry box to 2 characters max [duplicate]
(1 answer)
Closed 5 years ago.
How do I limit the input on a Entry to only 4 characters
from tkinter import *
window = Tk()
display = Entry(window)
display.grid()
You can do this by running a trace on the attribute textvariable of the entry widget. Whenever this variable is updated you will need to set the variable to it's own value up to the 4th character.
See below:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.sv = StringVar()
self.entry = Entry(root, textvariable = self.sv)
self.entry.pack()
self.sv.trace("w", lambda name, index, mode, sv=self.sv: self.callback(self.sv))
def callback(self, sv):
self.sv.set(self.sv.get()[:4])
root = Tk()
App(root)
root.mainloop()
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()