Я подозреваю что этот вопрос очень сложный (ну или невозможный). Но
я хотел бы узнать можно ли сделать подсветку синтаксиса в текстовом виджете ?
question@mail.ru
·
01.01.1970 03:00
Как сделать подсветку синтаксиса в tkinter
answer@mail.ru
·
01.01.1970 03:00
Предупреждение: реализация в ответе не оптимальная, будет тормозить при прокрутке на большом количестве строк. Для неучебных целей рекомендую использовать модуль
Нужно делать лексический разбор (парсинг) текста - разбивать текст на подсвечиваемые куски (токены), в зависимости от типа токена по-разному выделять куски текста. Для простоты можно взять готовый парсер, например, из библиотеки (ставится с помощью pip install pygments). Также можно использовать модуль из стандартной библиотеки python, если предполагается делать подсветку только для Python.
Ниже собранный на коленке пример с подсветкой ключевых слов и текстовых литералов (работает неоптимально, при каждом изменении удаляет всю подсветку, заново разбирает текст на токены, заново подсвечивает - в идеале нужно обрабатывать только видимые строки текста):
import tkinter as tkfrom pygments.lexers import PythonLexerfrom pygments.token import Tokenlexer = PythonLexer()root = tk.Tk()text = tk.Text(root)text.pack()# Создаем теги с разными свойствами, которые будем присваивать соответствующим типам токеновtext.tag_config(""keyword"", foreground='blue')text.tag_config(""string_literal"", foreground='red')# Прописываем соответствие типа токена тегу подсвет��иtoken_type_to_tag = { Token.Keyword: ""keyword"", Token.Operator.Word: ""keyword"", Token.Name.Builtin: ""keyword"", Token.Literal.String.Single: ""string_literal"", Token.Literal.String.Double: ""string_literal"",}def get_text_coord(s: str, i: int): """""" Из индекса символа получить ""координату"" в виде ""номер_строки_текста.номер_символа_в_строке"" """""" for row_number, line in enumerate(s.splitlines(keepends=True), 1): if i < len(line): retu f'{row_number}.{i}' i -= len(line)def on_edit(event): # Удалить все имеющиеся теги из текста for tag in text.tag_names(): text.tag_remove(tag, 1.0, tk.END) # Разобрать текст на токены s = text.get(1.0, tk.END) tokens = lexer.get_tokens_unprocessed(s) for i, token_type, token in tokens: print(i, token_type, repr(token)) # Отладочный вывод - тут видно какие типы токенов выдаются j = i + len(token) if token_type in token_type_to_tag: text.tag_add(token_type_to_tag[token_type], get_text_coord(s, i), get_text_coord(s, j)) # Сбросить флаг редактирования текста text.edit_modified(0)text.bind('<<Modified>>', on_edit)root.mainloop()Как добавить обработку других токенов, на примере комментариев: вставляем в текстовое поле комментарий, например # Комментарий, смотрим, что вывелось в консоль (в коде не зря оставлен отладочный вывод):
0 Token.Comment.Single '# Комментарий'13 Token.Text '\n'Т.е. комментарию соответствует класс токена Token.Comment.Single.
Дальше, добавляем тег с цветом для комментариев, пусть это будет серый:
text.tag_config(""comment"", foreground='gray')В словарь соответствий классов токенов тегам tkinter добавляем класс комментария, ставим ему в соответствие только что добавленный тег:
token_type_to_tag = { ... Token.Comment.Single: ""comment"",}Итог, видим, что комментарий стал выделяться серым цветом: