Tkinter ScrolledText Вставка текста Ошибка наследования - PullRequest
0 голосов
/ 08 января 2019

Я просмотрел большинство доступных сообщений Tkinter ScrolledText StackOverflow, включая описания найденного наследования: Учебник по наследованию и Наследование по классам . Тем не менее, я не могу понять в этом конкретном примере, почему я получаю следующую ошибку:

    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()

Этот вопрос был помечен как дубликат другого сообщения на Python в tkinter с возвращением 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()

Ответы [ 3 ]

0 голосов
/ 09 января 2019
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 методом. После разговора с Брайаном в комментариях я понял, что мы забыли инициализировать родительский класс в вашем классе SomeGui, что, вероятно, и стало причиной ошибки рекурсии, которую мы получили. Вероятно, есть способ убрать TextBoxClass, который я тоже пропускаю.

0 голосов
/ 04 февраля 2019

Благодаря вкладу друга и моих собственных экспериментов, интегрирующих элементы того, что сказали комментаторы, я пришел к решению своей проблемы пару недель назад.

Я знаю, что это было опровергнуто благодаря 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()
0 голосов
/ 08 января 2019

Ошибка говорит вам, что вы пытаетесь вызвать 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, а также дзену Python (явное лучше, чем неявное).

Наконец, есть еще одна проблема. Вы создаете два корневых окна, и программа tkinter может иметь только одно (за исключением очень необычных обстоятельств, а это не так). Один создается, когда вы делаете root = tk.Tk(), а второй - когда вы делаете sg=someGui(root), поскольку someGui наследуется от tk.Tk. Чтобы усугубить проблему, вы неправильно вызываете метод суперкласса __init__, поэтому экземпляр someGui не создан должным образом. В этом корень ошибки рекурсии, о которой вы писали в своем обновлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...