我得到了一段可以使用 Tkinter Text Widget 突出显示 Python 语法的代码。但是,我仍然无法突出显示“def”后的函数名称、“class”后的类名称以及“import”后的包名称。如果缺少了某些明显的信息,请温柔地将信息传达给我。
python.yaml
categories: keywords: color: orange matches: ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] variables: color: red4 matches: ['True', 'False', None] functions: color: "#525fe9" matches: ['abs',delattr','hash','memoryview','set','all','dict','help','min','setattr','any','dir','hex','next','slice','ascii','divmod','id','object','sorted','bin','enumerate','input','oct','staticmethod','bool','eval','int','open','str','breakpoint','exec','isinstance','ord','sum','bytearray','filter','issubclass','pow','super','bytes','float','iter','print','tuple','callable','format','len','property','type','chr','frozenset','list','range','vars','classmethod','getattr','locals','repr','zip','compile','globals','map','reversed','__import__','complex','hasattr','max',round'] numbers: color: pink strings: color: "#e16d5b"
highlighter.py 有助于突出显示从 python.yaml 文件中获取的单词。
import tkinter as tk import yaml class Highlighter: def __init__(self, text_widget, syntax_file): self.text_widget = text_widget self.syntax_file = syntax_file self.categories = None self.numbers_color = "blue" self.disallowed_previous_chars = ["_", "-", "."] self.parse_syntax_file() self.text_widget.bind('<KeyRelease>', self.on_key_release) def on_key_release(self, event=None): self.highlight() def parse_syntax_file(self): with open(self.syntax_file, 'r') as stream: config = yaml.safe_load(stream) self.categories = config['categories'] self.numbers_color = config['numbers']['color'] self.strings_color = config['strings']['color'] self.configure_tags() def callback_1(self,event): info_window = tk.Tk() info_window.overrideredirect(1) info_window.geometry("200x24+{0}+{1}".format(event.x_root-100, event.y_root-12)) label = tk.Label(info_window, text="Word definition goes here.") label.pack(fill=tk.BOTH) info_window.bind_all("<Leave>", lambda e: info_window.destroy()) # Remove popup when pointer leaves the window info_window.mainloop() def configure_tags(self): for category in self.categories.keys(): color = self.categories[category]['color'] self.text_widget.tag_configure(category, foreground=color) self.text_widget.tag_configure("number", foreground=self.numbers_color) self.text_widget.tag_configure("string", foreground=self.strings_color) self.text_widget.tag_bind("string","<Enter>", self.callback_1) def highlight(self, event=None): length = tk.IntVar() for category in self.categories: matches = self.categories[category]['matches'] for keyword in matches: start = 1.0 keyword = keyword + "[^A-Za-z_-]" idx = self.text_widget.search(keyword, start, stopindex=tk.END, count=length, regexp=1) while idx: char_match_found = int(str(idx).split('.')[1]) line_match_found = int(str(idx).split('.')[0]) if char_match_found > 0: previous_char_index = str(line_match_found) + '.' + str(char_match_found - 1) previous_char = self.text_widget.get(previous_char_index, previous_char_index + "+1c") if previous_char.isalnum() or previous_char in self.disallowed_previous_chars: end = f"{idx}+{length.get() - 1}c" start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) else: end = f"{idx}+{length.get() - 1}c" self.text_widget.tag_add(category, idx, end) start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) else: end = f"{idx}+{length.get() - 1}c" self.text_widget.tag_add(category, idx, end) start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) self.highlight_regex(r"(\d)+[.]?(\d)*", "number") self.highlight_regex(r"[\'][^\']*[\']", "string") self.highlight_regex(r"[\"][^\']*[\"]", "string") def highlight_regex(self, regex, tag): length = tk.IntVar() start = 1.0 idx = self.text_widget.search(regex, start, stopindex=tk.END, regexp=1, count=length) while idx: end = f"{idx}+{length.get()}c" self.text_widget.tag_add(tag, idx, end) self.text_widget.tag_bind("string","<Enter>", self.callback_1) start = end idx = self.text_widget.search(regex, start, stopindex=tk.END, regexp=1, count=length) if __name__ == '__main__': w = tk.Tk() x=tk.Text(w) x.pack(fill=tk.BOTH,expand=1) h = Highlighter(x, 'Path/to/python.yaml') w.mainloop()
为了突出显示 def 关键字后的函数名称、class 关键字后的类名称以及 import 后的包名称,您需要对代码进行一些增强。以下是改进的步骤:
def
class
import
def my_function
class MyClass
检测 import 和 from ... import 后的模块或包名,例如:import os, from sys import argv.
from ... import
import os
from sys import argv
高亮逻辑:
为这些标签设置不同的颜色。
更新 python.yaml 文件:
function_names
class_names
import_names
categories: keywords: color: orange matches: ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] function_names: color: purple matches: [] # 不需要在这里指定,代码中通过正则匹配 class_names: color: blue matches: [] # 不需要在这里指定,代码中通过正则匹配 import_names: color: green matches: [] # 不需要在这里指定,代码中通过正则匹配 numbers: color: pink strings: color: "#e16d5b"
highlighter.py
在 highlight 函数中添加以下正则表达式匹配:
highlight
def highlight(self, event=None): length = tk.IntVar() for category in self.categories: matches = self.categories[category]['matches'] for keyword in matches: start = 1.0 keyword = keyword + "[^A-Za-z_-]" idx = self.text_widget.search(keyword, start, stopindex=tk.END, count=length, regexp=1) while idx: char_match_found = int(str(idx).split('.')[1]) line_match_found = int(str(idx).split('.')[0]) if char_match_found > 0: previous_char_index = str(line_match_found) + '.' + str(char_match_found - 1) previous_char = self.text_widget.get(previous_char_index, previous_char_index + "+1c") if previous_char.isalnum() or previous_char in self.disallowed_previous_chars: end = f"{idx}+{length.get() - 1}c" start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) else: end = f"{idx}+{length.get() - 1}c" self.text_widget.tag_add(category, idx, end) start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) else: end = f"{idx}+{length.get() - 1}c" self.text_widget.tag_add(category, idx, end) start = end idx = self.text_widget.search(keyword, start, stopindex=tk.END, regexp=1) self.highlight_regex(r"(\d)+[.]?(\d)*", "number") self.highlight_regex(r"[\'][^\']*[\']", "string") self.highlight_regex(r"[\"][^\']*[\"]", "string") # Highlight function names self.highlight_regex(r"\bdef\s+(\w+)", "function_names") # Highlight class names self.highlight_regex(r"\bclass\s+(\w+)", "class_names") # Highlight import names self.highlight_regex(r"\bimport\s+(\w+)|\bfrom\s+(\w+)", "import_names")
匹配函数名称: 正则表达式 \bdef\s+(\w+) 用于匹配 def 后的函数名称。
\bdef\s+(\w+)
匹配类名称: 正则表达式 \bclass\s+(\w+) 用于匹配 class 后的类名称。
\bclass\s+(\w+)
匹配包名称: 正则表达式 \bimport\s+(\w+)|\bfrom\s+(\w+) 用于匹配 import 和 from ... import 语句后的包名称。
\bimport\s+(\w+)|\bfrom\s+(\w+)
新标签: 为 function_names、class_names 和 import_names 配置独特的颜色,便于区分。
在 Text 小部件中输入以下代码时:
def my_function(): pass class MyClass: pass import os from sys import argv
以下部分将高亮: - my_function 为紫色。 - MyClass 为蓝色。 - os 和 sys 为绿色。
my_function
MyClass
os
sys