I’ve created this simple GUI:
from tkinter import *
root = Tk()
def grabText(event):
print(entryBox.get())
entryBox = Entry(root, width=60).grid(row=2, column=1, sticky=W)
grabBtn = Button(root, text="Grab")
grabBtn.grid(row=8, column=1)
grabBtn.bind('<Button-1>', grabText)
root.mainloop()
I get the UI up and running. When I click on the Grab button, I get the following error on the console:
C:Python> python.exe myFilestestBed.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:Pythonliblib-tkTkinter.py", line 1403, in __call__
return self.func(*args)
File "myFilestestBed.py", line 10, in grabText
if entryBox.get().strip()=="":
AttributeError: 'NoneType' object has no attribute 'get'
Why is entryBox set to None?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
The grid, pack and place functions of the Entry object and of all other widgets returns None. In python when you do a().b(), the result of the expression is whatever b() returns, therefore Entry(...).grid(...) will return None.
You should split that on to two lines like this:
entryBox = Entry(root, width=60) entryBox.grid(row=2, column=1, sticky=W)
That way you get your Entry reference stored in entryBox and it’s laid out like you expect. This has a bonus side effect of making your layout easier to understand and maintain if you collect all of your grid and/or pack statements in blocks.
Method 2
Change this line:
entryBox=Entry(root,width=60).grid(row=2, column=1,sticky=W)
into these two lines:
entryBox=Entry(root,width=60) entryBox.grid(row=2, column=1,sticky=W)
Just as you already correctly do for grabBtn!
Method 3
For entryBox.get() to access get() method you need Entry object but Entry(root, width=60).grid(row=2, column=1, sticky=W) returns None.
entryBox = Entry(root, width=60) creates a new Entry Object.
Moreover, you won’t need
entryBox = entryBox.grid(row=2, column=1, sticky=W) as it will rewrite entryBox with None
Just replace entryBox = entryBox.grid(row=2, column=1, sticky=W)
with
entryBox = Entry(root, width=60) entryBox.grid(row=2, column=1, sticky=W)
Method 4
Alternative solution for Python3.8+ versions that allows to put all of this in one line using the walrus operator:
(entryBox := Entry(root, width=60)).grid(row=2, column=1, sticky=W)
Now entryBox will refer to the Entry widget and also get packed.
For chars per line management I can suggest sth like this:
(var := Button(
text='fine', command=some_func, width=20, height=15, activebackground='grey'
)).grid(row=0, column=0, columnspan=0, rowspan=0, sticky='news')
But at that point might as well just do this “normally” (as suggested by other answers)
Sources:
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0