3

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

  • Every widget in tkinter has the necessary argument *master*. If the master isnt defined the root window `tk.Tk()` is set by default. So if there is no master and no root window it throws a error. [Reference](http://epydoc.sourceforge.net/stdlib/Tkinter.StringVar-class.html) – Thingamabobs May 02 '21 at 06:47

1 Answers1

1

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()
Henry Yik
  • 22,275
  • 4
  • 18
  • 40
  • Hi Henry, first of all thank you very much for your fast reply, this is a lot of new information for me, which I have to discover and research. I will have a more deeper look into `__init__.py` and the Variable class. I confess, that my background is more C and C# like, so I am still trying to adapt to Python. Thank you again and with best greatings, Lars – Lars Lindner May 02 '21 at 17:41