我查看了大多数可用的Tkinter ScrolledText StackOverflow帖子,包括发现的继承描述:Inheritance Tutorial和Inheritance with Classes。但是,在这个特定示例中,我似乎无法理解为什么会出现以下错误:
textBoxClass(self.parent).textDropIn(self.parent).insert(tk.INSERT,"This is the text to add.")
AttributeError: 'NoneType' object has no attribute 'insert'
我了解我不存在'insert'
的属性,但是基于我的类定义调用,我不理解为什么textDropIn
函数不具有ScrolledText
的属性class textBoxClass(tkst.ScrolledText):
的值,但是我怀疑是不正确的实例化(?),这就是ScrolledText
属性的继承在函数中不可用的原因。
我的另一半怀疑我必须从ScrolledText
类中的someGui
继承属性才能在类方法中调用它们,但是我不确定。
完整代码:
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.scrolledtext as tkst
class someGui(tk.Tk):
def __init__(self,parent):
self.parent=parent
self.Window()
textBoxInstance=textBoxClass(self.parent)
def Window(self):
self.parent.configure(bg='white')
self.parent.geometry("1000x500")
self.parent.title("Example Window")
self.someFrame = ttk.Frame(self.parent)
self.someFrame.grid(row=0, column=0, sticky=(N,S,E,W))
textBoxSeparate=textBoxClass(self.parent)
self.someFunction()
def someFunction(self):
#otherstuff
textBoxClass(self.parent).textDropIn(self.parent).insert(tk.INSERT,"This is the text to add.")
class textBoxClass(tkst.ScrolledText):
def __init__(self,parent):
self.root=parent
self.textDropIn(self.root)
def textDropIn(self,parent):
self.someText = tkst.ScrolledText(master=self.root, wrap=tk.WORD, width=50, height=20)
self.someText.grid(row=0, column=4, rowspan=7, columnspan=4, pady=20, padx=20)
def main():
root =tk.Tk()
sg=someGui(root)
root.mainloop()
if __name__=='__main__':
main()
此问题已被标记为另一个tkinter python帖子的重复项,在None
属性调用的上下文中返回了get()
,但是我进行了与建议相同的行分隔编辑该用户,而没有解决问题。如果有人可以详细解释为什么重复的话,我很乐意删除这个问题。但是,我不明白为什么会这样。
根据布莱恩的第一个答案进行编辑
这是我的理解。我进行了编辑,但在此过程中遇到了一些错误。我删除了tkst.ScrolledText
,因为我不正确地继承了属性并调用了它的实例。我在parent
定义中的textDropIn
函数中删除了__init__
作为属性,并在textBoxClass
中删除了它们各自的调用。我也将self.textBox=textBoxClass(self.parent)
添加到了__init__
类的someGui
中,但是根据我的编辑,我遇到了TypeError
和RecursionError
。当前,它是带有当前版本代码的RecursionError
。这是由于self.textBox.textDropIn()
没有传递任何参数。
from tkinter import ttk
import tkinter as tk
import tkinter.scrolledtext as tkst
class someGui(tk.Tk):
def __init__(self,parent):
self.parent=parent
self.Window()
self.textBox=textBoxClass(self.parent) #saving the instance
def Window(self):
self.parent.configure(bg='white')
self.parent.geometry("1000x500")
self.parent.title("Example Window")
self.someFrame = ttk.Frame(self.parent)
self.someFrame.grid(row=0, column=0, sticky='nesw') #changed sticky definition for tk requirements
textBoxSeparate=textBoxClass(self.parent) # the initial inclusion of the textbox in the frame
self.someFunction() #no input needed
def someFunction(self):
#otherstuff
self.textBox.textDropIn() #there is no parent attribute in textDropIn, so I removed it
self.textBox.insert(tk.INSERT, "Some test text.") #split call to two lines and changed to tk.INSERT
class textBoxClass(): #removed tkst.ScrolledText in class call because instance was created in textDropIn
def __init__(self,parent):
self.root=parent
super().__init__() #kept receiving TypeError: object.__init__() takes no arguments, thus removed args
self.textDropIn() #removed parent attribute from function call
def textDropIn(self): #removed parent attribute from definition
self.someText = tkst.ScrolledText(master=self.root, wrap=tk.WORD, width=50, height=20)
self.someText.grid(row=0, column=4, rowspan=7, columnspan=4, pady=20, padx=20)
def main():
root =tk.Tk()
sg=someGui(root)
root.mainloop()
if __name__=='__main__':
main()
答案 0 :(得分:2)
错误告诉您您正在尝试对insert
的对象调用None
。因此,让我们看一下您在哪里呼叫insert
:
textBoxClass(self.parent).textDropIn(self.parent).insert(tk.INSERT,"This is the text to add.")
根据错误消息,我们必须得出结论,textBoxClass(self.parent).textDropIn(self.parent)
是None
。确实,当我们查看textDropIn
方法的定义时,它不会显式返回任何内容。因为它没有显式返回任何内容,所以它将返回None
。因此,该代码与完成None.insert(...)
相同,因此也将得到错误。
有两个明显的解决方案。如果希望像这样将方法链接在一起(例如:.textDropIn(...).insert(...)
),则需要确保链接中的每个步骤都返回原始对象。您可以这样操作:
def someFunction(self):
#otherstuff
textBoxClass(self.parent).textDropIn(self.parent).insert(tk.INSERT,"This is the text to add.")
return self
另一种方法是将一个长语句分成两部分:
textBoxClass(self.parent).textDropIn(self.parent)
textboxClass(self.parent).insert(tk.INSERT,"This is the text to add.")
但是,这不是调用textDropIn
和insert
的正确方法。相反,您需要直接在类的实例上调用它。不幸的是,您没有保存对实例的引用,因此第一件事是通过保存实例来解决该问题:
class someGui(tk.Tk):
def __init__(self,parent):
self.parent=parent
self.Window()
self.textBox = textBoxClass(self.parent)
然后,您可以在该实例上调用方法:
def someFunction(self):
#otherstuff
self.textBox.textDropIn(self.parent)
self.textbox.insert(tk.INSERT,"This is the text to add.")
由于您从不使用parent
中的textDropIn
属性,因此建议从定义和调用中都删除该参数。
此外,如果所有类名都以大写字母开头,则代码将更易于理解。您应将textBoxClass
更改为TextBoxClass
,将someGui
更改为SomeGui
。该命名约定在python世界中是通用的。有关标准命名约定的更多信息,请参见PEP8。
还有另一个问题。 textBoxClass
既继承自ScrolledText
,又创建了它的实例。您应该做一个或另一个。我不能完全说出您要完成的工作,但是扩展现有类的通常方法是使用类似这样的东西(请注意super
的用户):
class textBoxClass(tkst.ScrolledText):
def __init__(self,parent):
self.root=parent
super().__init__(self, parent)
self.textDropIn(self.root)
代码中的另一个问题是您两次导入tkinter:
from tkinter import *
...
import tkinter as tk
这使您的代码很难理解。您需要选择一种导入方法并坚持使用。我个人认为第二个版本是最好的,因为它遵循PEP8和zen python(显式优于隐式)。
最后,还有另一个问题。您正在创建两个根窗口,一个tkinter程序只能有一个(除非在非常特殊的情况下不是这样)。一种是在您执行root = tk.Tk()
时创建的,第二种是在您执行sg=someGui(root)
时创建的,因为someGui
继承自tk.Tk
。为了解决这个问题,您没有正确地调用超类__init__
方法,因此someGui
实例的构造不正确。这就是您在更新中所写的递归错误的根源。
答案 1 :(得分:0)
from tkinter import ttk
import tkinter as tk
import tkinter.scrolledtext as tkst
class SomeGui(tk.Tk):
def __init__(self):
super().__init__()
self.textBox=TextBoxClass(self) #saving the instance
self.configure(bg='white')
self.geometry("1000x500")
self.title("Example Window")
self.someFrame = ttk.Frame(self)
self.someFrame.grid(row=0, column=0, sticky='nesw') #changed sticky definition for tk requirements
self.someFunction() #no input needed
def someFunction(self):
#otherstuff
self.textBox.textDropIn() #there is no parent attribute in textDropIn, so I removed it
self.textBox.someText.insert(tk.INSERT, "here we go")
class TextBoxClass(tkst.ScrolledText): #removed tkst.ScrolledText in class call because instance was created in textDropIn
def __init__(self,parent):
self.root=parent
tkst.ScrolledText.__init__(self) #kept receiving TypeError: object.__init__() takes no arguments, thus removed args
self.textDropIn()
def textDropIn(self): #removed parent attribute from definition
self.someText = tkst.ScrolledText(master=self.root, wrap=tk.WORD, width=50, height=20)
self.someText.grid(row=0, column=4, rowspan=7, columnspan=4, pady=20, padx=20)
def main():
sg=someGui()
sg.mainloop()
if __name__=='__main__':
main()
好吧,我已经进行了一些更改,并使其全部与您的someFunction
方法一起使用。在与Bryan进行评论之后,我意识到我们忘记了在SomeGui类中初始化父类,这可能是导致我们递归错误的原因。我也可能忽略了一种整理TextBoxClass
的方法。
答案 2 :(得分:0)
通过朋友的贡献和我自己的实验,整合了评论者所说的内容,几周前,我为我的问题找到了解决方案。
我知道此问题已被解决方案所需的Tkinter AttributeError否决了,但是AttributeError修复程序的简单集成无法解决我的问题,并且这是与我的原始问题有关的未知错误。这是回答我的原始问题的最佳答案。
我要理解的最大问题是super().__init__
中textDropIn
函数中的textBoxClass
调用。在此之前,我是从tkst.ScrolledText
继承的,但是我创建的窗口小部件不正确。
最终的解决方案使我可以调用textBoxClass
的类实例,并在与someGui
类关联的所有子功能中向窗口中写入文本,这是我的最初目标。
我将注释的代码留在那里,以反映一些过去无法正常工作的想法。
from tkinter import ttk
import tkinter as tk
import tkinter.scrolledtext as tkst
class someGui(tk.Tk):
def __init__(self, parent):
self.parent=parent
self.textBox=textBoxClass(self.parent) #saving the instance
self.Window()
def Window(self):
print("window")
self.parent.configure(bg='white')
self.parent.geometry("1000x500")
self.parent.title("Example Window")
self.someFrame = ttk.Frame(self.parent)
self.someFrame.grid(row=0, column=0, sticky='nesw') #changed sticky definition for tk requirements
# textBoxSeparate=textBoxClass(self.parent) # the initial inclusion of the textbox in the frame
# textBoxSeparate.place(relx=0.5, rely=0.025, anchor='nw') #added this so textBoxSeparate doesn't overlap textbox
# textBoxSeparate.insert(tk.INSERT, "textBoxSeparate sample text")
self.someFunction() #no input needed
# self.newFunction()
def someFunction(self):
#Both of the following ways of adding text work
self.textBox.textDropIn() #there is no parent attribute in textDropIn, so I removed it
self.textBox.insert(tk.INSERT, "textbox sample text\n") #split call to two lines and changed to tk.INSERT
self.newFunction()
def newFunction(self):
self.textBox.insert(tk.INSERT,"another line of text")
class textBoxClass(tkst.ScrolledText):
def __init__(self, parent):
self.root = parent
#super().__init__(...) allows this class to inherit the tkst.ScrolledText class. Therefore, initializing the textBoxClass
#will automaticaly allow it to have all the same methods/attributes as initializing tkst.ScrolledText(), in addition to the methods/attr you add below.
super().__init__(master=self.root, wrap=tk.WORD, borderwidth=1, relief="solid",width=50, height=20) #added a border for better visualization
#self.textDropIn() #removed parent attribute from function call
def textDropIn(self): #removed parent attribute from definition
self.grid(row=0, column=4, rowspan=7, columnspan=4, pady=20, padx=20)
# self.insert(tk.INSERT, "textDropIn sample text\n")
def main():
root =tk.Tk()
sg=someGui(root)
root.mainloop()
if __name__=='__main__':
main()