【问题标题】:Python + Tkinter: "AttributeError"Python + Tkinter:“属性错误”
【发布时间】:2021-07-24 22:21:19
【问题描述】:

我也没有太多的 Python 实践,并且在理解错误时存在一个基本问题:AttributeError: 'NoneType' object has no attribute '_root',它仅在我定义 dec 变量 BEFORE 时出现strong> 定义主窗口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()

为什么我必须定义 first 窗口和 than 布尔变量?我对 Tkinter 有什么不明白的地方?

感谢大家的大力帮助和最良好的祝愿 拉尔斯

【问题讨论】:

  • tkinter 中的每个小部件都有必要的参数 master。如果未定义主窗口,则默认设置根窗口tk.Tk()。因此,如果没有主窗口且没有根窗口,则会引发错误。 Reference

标签: python tkinter mainloop


【解决方案1】:

您实际上可以在 tkinter 的 __init__.py 上查看。

StringVarIntVarDoubleVarBooleanVar都继承自类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

    ...

因此,您会看到创建 tkinter 变量时,它会查找存储为全局变量 _default_rootmaster(如果您尚未创建 tk 实例,则为 None),即为什么你会收到AttributeError

但您可能会问,为什么这不适用于小部件?那是因为Widgets 继承自另一个名为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

所以你会看到,当你创建一个没有主控的新小部件时,BaseWidget 实际上会创建一个 tk 的新实例作为_default_root,而不是Variable。我的猜测是没有理由只为变量创建Tk 的实例,因为不需要在屏幕上呈现任何内容,但同样不能应用于小部件。

因此,即使您自己没有创建Tk 实例,以下内容也不会引发错误:

import tkinter as tk

a = tk.Button(text="ABC")

b = tk.BooleanVar()

【讨论】:

  • 您好亨利,首先非常感谢您的快速回复,这对我来说是很多新信息,我必须发现和研究。我将对__init__.py 和Variable 类进行更深入的研究。我承认,我的背景更喜欢 C 和 C#,所以我仍在努力适应 Python。再次感谢您,并致以最诚挚的敬意,Lars