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

1
  • 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 Commented May 2, 2021 at 6:47

1 Answer 1

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()
Sign up to request clarification or add additional context in comments.

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.