Замена tkinter.Метод вставки текста

#python #user-interface #tkinter #tkinter-text

#python #пользовательский интерфейс #tkinter #tkinter-текст

Вопрос:

Я пытался заменить (во время выполнения) унаследованный метод insert() для подкласса tkinter.Текст. Метод замены выполняет несколько строк кода перед вызовом метода вставки () родительского класса (tkinter.Text). Однако во время выполнения python выдает следующую ошибку.

 Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 1885, in __call__
    return self.func(*args)
  File ".../expts/test.py", line 20, in callback
    text.insert("1.0", "howdy")
  File ".../expts/test.py", line 14, in new_insert
    tk.Text.insert(text, index, chars, *args)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 3740, in insert
    self.tk.call((self._w, 'insert', index, chars)   args)
AttributeError: type object 'Text' has no attribute 'tk'
 

Следующий код представляет собой упрощенную версию моего основного кода.

 import tkinter as tk
import types

class TextChild(tk.Text):
    def __init__(self, *args, **kwargs):
        tk.Text.__init__(self, *args, **kwargs)

root = tk.Tk()
text = TextChild(root)
text.pack()

def new_insert(text, index, chars, *args):
    print("Does some work...")
    tk.Text.insert(text, index, chars, *args)

text.insert = types.MethodType(new_insert, tk.Text)

def callback():
    global text
    text.insert("1.0", "howdy")

button = tk.Button(master=root,text="Button", command=callback)
button.pack()

root.mainloop()
 

Ответ №1:

Это проще сделать внутри унаследованного класса:

 class TextChild(tk.Text):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def insert(self, index, chars, *args):
        print("Does some work ...")
        # call original insert()
        super().insert(index, chars, *args)
 

Комментарии:

1. Я разрабатываю плагин для существующего приложения. Итак, я не могу обновить существующие определения. Я могу изменять методы / обратные вызовы только в течение срока службы плагина.

2. @SamZeleke Тогда в вашем случае TextChild нет необходимости, и вы можете использовать lambda вместо этого: text.insert = lambda *args: new_insert(text, *args) .

3. Вы правы. TextChild так же прост, потому что я упростил код для вопроса. Класс на самом деле намного больше.

Ответ №2:

Чтобы обратиться к вашему исходному методу, вы смешиваете аргументы для types.MethodType . Аргументами являются метод и объект.

 text.insert = types.MethodType(new_insert, text)