I also have not a lot of practice with Python and have a fundamental problem of understanding the error: AttributeError: 'NoneType' object has no attribute '_root'
, which only appears, when I define the dec variable BEFORE defining the main window win:
import tkinter as tk
from tkinter import ttk
from tkinter import *
# This variable must be defined AFTER definition of the Tk() window!
dec = tk.BooleanVar()
# Main window
win = Tk()
# # This variable must be defined AFTER definition of the Tk() window!
# dec = tk.BooleanVar()
decreaseButton = Checkbutton(win, text = "Decrease (optional)", variable = dec)
decreaseButton.grid(row=1, column=1, sticky='W')
# Runs the event loop of Tkinter
win.mainloop()
Why do I have to define first the window and than the Boolean variable? What did I not understand from Tkinter?
Thank you everybody for your great help and with best wishes Lars
You can actually look this up at tkinter's __init__.py
.
StringVar
, IntVar
, DoubleVar
and BooleanVar
all inherits from the class Variable
:
class Variable:
...
_default = ""
_tk = None
_tclCommands = None
def __init__(self, master=None, value=None, name=None):
...
if name is not None and not isinstance(name, str):
raise TypeError("name must be a string")
global _varnum
if not master:
master = _default_root
self._root = master._root()
self._tk = master.tk
...
So you see when a tkinter variable is created, it will lookup for a master
stored as a global variable _default_root
(which is None
if you have yet to create a tk
instance), which is why you receive a AttributeError
.
But you might ask, why the same does not apply to widgets? That is because Widgets
inherits from a different base class called BaseWidgets
:
class BaseWidget(Misc):
...
def _setup(self, master, cnf):
...
if _support_default_root:
global _default_root
if not master:
if not _default_root:
_default_root = Tk() <--- create a new instance of `Tk`
master = _default_root
So you see when you create a new widget without a master, BaseWidget
will actually create a new instance of tk
as _default_root
as opposed to Variable
. My guess is that there is no reason to create an instance of Tk
just for a variable since nothing needs to be rendered on screen, but the same cannot be applied for a widget.
As such, the below doesn't throw an error even you did not create a Tk
instance yourself:
import tkinter as tk
a = tk.Button(text="ABC")
b = tk.BooleanVar()