It is a very common error in Tkinter. The problem is the use of grid
, place
or pack
on the same line where the widget is instantiated. It is very well that of saving lines but sometimes has its consequences ツ.
If this is done:
mainframe = ttk.Frame(root, ).grid()
mainframe
is not a ttk.Frame
object, it is the return of the grid
method, which returns nothing ( None
). That's why the error says:
TypeError: 'NoneType' object does not support item assignment
If you want to use the name of the object to change its attributes later, it is necessary to separate the instance of the call from the grid
method:
mainframe = ttk.Frame(root)
mainframe.grid()
You can see the difference by doing something as simple as printing the mainframe variable in both cases:
import tkinter as tk
from tkinter import ttk
root=tk.Tk()
mainframe0 = ttk.Frame(root).grid()
print(type(mainframe0))
mainframe1 = ttk.Frame(root)
mainframe1.grid()
print(type(mainframe1))
At the start we see the difference:
>>> <class 'NoneType'>
>>> <class 'tkinter.ttk.Frame'>
On the other hand, it is not a proper error but if a very bad practice that for some reason is very extended in tutorials of Tkinter, you should never import a module in Python of the form (except justified cases, mainly to merge two namespaces):
from tkinter import *
Your code is simple and will not give you problems in principle but it can cause many headaches using complex modules or in medium large projects. This form of import exposes all the identifiers of the module in your current namespace. In principle you do not know the name of all classes, objects or functions contained in the module so you can end up overwriting with your own functions in your namespace Tkinter functions or vice versa without realizing it. On the other hand, it hinders the legibility of the code by third parties ("Explicit better than implicit").
The proper way is to use one of these:
from tkinter import Tk, Button, Frame...
import tkinter
import tkinter as tk
Your code could look like this:
import tkinter as tk
from tkinter import ttk
root=tk.Tk()
mainframe = ttk.Frame(root)
mainframe.grid()
mainframe['padding'] = 5, 10
etiqueta = ttk.Label(root, text="try")
etiqueta.grid(row=0, column=2)
buton=ttk.Button(mainframe, text="push here", command=root.quit)
buton.grid(row=1, column=24)
root.mainloop()
Result:
Edit:
Parameters weidht
and height
are specified the same as the rest, except that if we want to avoid the automatic adjustment carried out by the layout and that the widget is forced to take those measures we need to use jointly The method: grid_propagate()
import tkinter as tk
from tkinter import ttk
root=tk.Tk()
mainframe = ttk.Frame(root)
mainframe.grid()
mainframe['padding'] = 5, 10
mainframe['width'] = 100
mainframe['height'] = 100
mainframe.grid_propagate(0)
etiqueta = ttk.Label(root, text="try")
etiqueta.grid(row=0, column=2)
buton=ttk.Button(mainframe, text="push here", command=root.quit)
buton.grid(row=1, column=24)
root.mainloop()