Вы можете не осознавать этого, но вы пытаетесь сделать что-то очень сложное в Tkinter.Хотя текстовые теги виджетов являются мощной концепцией, у них есть некоторые недостатки, когда речь идет о создании чего-то вроде редактора wysywig.
Вам нужно немного изменить свой подход.Вместо вставки пробелов, я думаю, что лучшее решение - добавить привязки, которые применяют (или удаляют) ваши теги каждый раз, когда вставляется символ.У этого есть свой собственный набор проблем, но с достаточным вниманием к деталям вы можете преодолеть их.Мы можем сделать это с помощью пользовательской привязки ключа.
Когда вы вставляете символ в текстовый виджет, это обрабатывается привязкой к событию <Key>
в классе текстового виджета.Таким образом, мы можем привязать к <Key>
, чтобы добавить тег.Однако, если мы добавим привязку к <Key>
в виджете, это вызовет перед привязкой класса, что означает, что наш код будет выполняться до вставленного символа, а не после.Мы будем пытаться изменить что-то, что еще не было вставлено в виджет.
Один из способов решить эту проблему - привязать к клавише release вместо нажатия клавиши,так как символ вставлен в печать.Однако подумайте о сценарии, в котором пользователь нажимает и удерживает клавишу - будет введено несколько символов, но вы можете получить только одно событие нажатия клавиши.Так что это решение не особенно хорошо.
Другое решение состоит в том, чтобы каким-то образом организовать нашу пользовательскую привязку, которая произойдет после привязки по умолчанию.Для этого нам нужно сделать две вещи: 1) настроить «теги привязки», чтобы виджет имел дополнительный тег после тега класса, и 2) добавить привязку к этому новому тегу привязки.
Тамнедостатки этого подхода тоже.Не из-за тегов связывания, а потому, что нужно обрабатывать гораздо больше событий, кроме <Key>
(например, control-v для вставки не обрабатывается привязкой <Key>
, поэтому вам придется добавитьособый случай для вставки).
При этом, это решение может быть достаточно хорошим для вас или, по крайней мере, достаточно хорошим, чтобы помочь вам лучше понять проблему, и понимание проблемы часто является самым большим препятствием для поискарешение.
В следующем примере у меня есть текстовый виджет с дополнительным тегом привязки с именем «CustomText», который мы помещаем после стандартного тега привязки «Текст».Я добавил привязку к этому тегу для события <Key>
, а в обработчике просто применил соответствующие теги к только что вставленному символу.
Вам нужно будет добавить свой собственный код для обработки вставки в буфер обмена и проблему обработки конфликтующих тегов (например, двух тегов, каждый со своим собственным шрифтом).Надеюсь, что этот пример послужит вдохновением
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.tag_vars = {
"underline": tk.IntVar(),
"red": tk.IntVar(),
}
self.text = MyText(self, width=40, height=8)
self.text.tag_configure("red", foreground="red")
self.text.tag_configure("underline", underline=True)
toolbar = tk.Frame(self)
self.underline = tk.Checkbutton(self, text="Underline",
onvalue = True, offvalue=False,
variable = self.tag_vars["underline"]
)
self.red = tk.Checkbutton(self, text="Red",
onvalue = True, offvalue=False,
variable = self.tag_vars["red"]
)
self.underline.pack(in_=toolbar, side="left")
self.red.pack(in_=toolbar, side="left")
toolbar.pack(side="top", fill="x")
self.text.pack(side="top", fill="both", expand=True)
class MyText(tk.Text):
def __init__(self, parent, *args, **kwargs):
tk.Text.__init__(self, *args, **kwargs)
self.parent = parent
# add a new bind tag, "CustomText" so we
# can have code run after the class binding
# has done it's work
bindtags = list(self.bindtags())
i = bindtags.index("Text")
bindtags.insert(i+1, "CustomText")
self.bindtags(tuple(bindtags))
# set a binding that will fire whenever a
# self-inserting key is pressed
self.bind_class("CustomText", "<Key>", self.OnKey)
def OnKey(self, event):
# we are assuming this is called whenever
# a character is inserted. Apply or remove
# each tag depending on the state of the checkbutton
for tag in self.parent.tag_vars.keys():
use_tag = self.parent.tag_vars[tag].get()
if use_tag:
self.tag_add(tag, "insert-1c", "insert")
else:
self.tag_remove(tag, "insert-1c", "insert")
if __name__ == "__main__":
app = SampleApp()
app.mainloop()