任何人都可以解释如何向 Tkinter
Text
小部件添加语法突出显示吗?
每次程序找到匹配的单词时,它都会将该单词着色为我想要的颜色。例如:将单词
tkinter
涂成粉红色,将in
涂成蓝色。但是当我输入 Tkinter
时,它会将 Tk--ter
着色为黄色,将 in
着色为蓝色。
我该如何解决这个问题?谢谢!
这是tfpf 答案的扩展。
当您调用
ic.make_pat()
时,它会返回用于 Python 格式化的整个正则表达式。虽然在一些额外的表达方式中使用 OR
看起来很方便,但它并没有真正给你太多的控制权,而且很快就会变得很麻烦。一种可能更有用且绝对更可定制的方法是打印/复制/粘贴ic.make_pat()
,并将其分解,如下所示。这还有一个额外的副作用,即您不必担心如何在 python 版本中调用 ic.make_pat()
,因为执行此操作后,您根本不会使用 ic.make_pat()
。
#syntax highlighter patterns
KEYWORD = r"\b(?P<KEYWORD>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)\b"
EXCEPTION = r"([^.'\"\\#]\b|^)(?P<EXCEPTION>ArithmeticError|AssertionError|AttributeError|BaseException|BlockingIOError|BrokenPipeError|BufferError|BytesWarning|ChildProcessError|ConnectionAbortedError|ConnectionError|ConnectionRefusedError|ConnectionResetError|DeprecationWarning|EOFError|Ellipsis|EnvironmentError|Exception|FileExistsError|FileNotFoundError|FloatingPointError|FutureWarning|GeneratorExit|IOError|ImportError|ImportWarning|IndentationError|IndexError|InterruptedError|IsADirectoryError|KeyError|KeyboardInterrupt|LookupError|MemoryError|ModuleNotFoundError|NameError|NotADirectoryError|NotImplemented|NotImplementedError|OSError|OverflowError|PendingDeprecationWarning|PermissionError|ProcessLookupError|RecursionError|ReferenceError|ResourceWarning|RuntimeError|RuntimeWarning|StopAsyncIteration|StopIteration|SyntaxError|SyntaxWarning|SystemError|SystemExit|TabError|TimeoutError|TypeError|UnboundLocalError|UnicodeDecodeError|UnicodeEncodeError|UnicodeError|UnicodeTranslateError|UnicodeWarning|UserWarning|ValueError|Warning|WindowsError|ZeroDivisionError)\b"
BUILTIN = r"([^.'\"\\#]\b|^)(?P<BUILTIN>abs|all|any|ascii|bin|breakpoint|callable|chr|classmethod|compile|complex|copyright|credits|delattr|dir|divmod|enumerate|eval|exec|exit|filter|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|isinstance|issubclass|iter|len|license|locals|map|max|memoryview|min|next|oct|open|ord|pow|print|quit|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|sum|type|vars|zip)\b"
DOCSTRING = r"(?P<DOCSTRING>(?i:r|u|f|fr|rf|b|br|rb)?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?|(?i:r|u|f|fr|rf|b|br|rb)?\"\"\"[^\"\\]*((\\.|\"(?!\"\"))[^\"\\]*)*(\"\"\")?)"
STRING = r"(?P<STRING>(?i:r|u|f|fr|rf|b|br|rb)?'[^'\\\n]*(\\.[^'\\\n]*)*'?|(?i:r|u|f|fr|rf|b|br|rb)?\"[^\"\\\n]*(\\.[^\"\\\n]*)*\"?)"
TYPES = r"\b(?P<TYPES>bool|bytearray|bytes|dict|float|int|list|str|tuple|object)\b"
NUMBER = r"\b(?P<NUMBER>((0x|0b|0o|#)[\da-fA-F]+)|((\d*\.)?\d+))\b"
CLASSDEF = r"(?<=\bclass)[ \t]+(?P<CLASSDEF>\w+)[ \t]*[:\(]" #recolor of DEFINITION for class definitions
DECORATOR = r"(^[ \t]*(?P<DECORATOR>@[\w\d\.]+))"
INSTANCE = r"\b(?P<INSTANCE>super|self|cls)\b"
COMMENT = r"(?P<COMMENT>#[^\n]*)"
SYNC = r"(?P<SYNC>\n)"
然后您可以按照适合您的顺序连接所有这些模式,如下所示:
PROG = rf"{KEYWORD}|{BUILTIN}|{EXCEPTION}|{TYPES}|{COMMENT}|{DOCSTRING}|{STRING}|{SYNC}|{INSTANCE}|{DECORATOR}|{NUMBER}|{CLASSDEF}"
您可能会注意到
DEFINITION
不存在于上述任何模式中。这是因为上面的模式是针对.prog
的,但是DEFINITION
模式是由.idprog
决定的。下面是我的。我希望类定义具有不同的颜色,因此我的模式忽略了前面带有 class
的定义。如果您不打算对 DEFINITION
做出一些例外,则根本不必搞乱它。
#original - r"\s+(\w+)"
IDPROG = r"(?<!class)\s+(\w+)"
接下来要考虑的是
tagdefs
。您无需逐行添加/修改关键点,只需预定义 tagdefs
。下面是一个例子。请注意,上面第一组模式中使用的每个 regex group
名称都用下面对象中的键表示。另请注意,此处包含 DEFINITION
。下面的每个对象都变为 options
的 tag_configure
,并且您可以使用 option
接受的任何 tag_configure
。颜色和字体是我自己的,示例中不需要包含它们。
TAGDEFS = { 'COMMENT' : {'foreground': CHARBLUE , 'background': None},
'TYPES' : {'foreground': CLOUD2 , 'background': None},
'NUMBER' : {'foreground': LEMON , 'background': None},
'BUILTIN' : {'foreground': OVERCAST , 'background': None},
'STRING' : {'foreground': PUMPKIN , 'background': None},
'DOCSTRING' : {'foreground': STORMY , 'background': None},
'EXCEPTION' : {'foreground': CLOUD2 , 'background': None, 'font':FONTBOLD},
'DEFINITION' : {'foreground': SAILOR , 'background': None, 'font':FONTBOLD},
'DECORATOR' : {'foreground': CLOUD2 , 'background': None, 'font':FONTITAL},
'INSTANCE' : {'foreground': CLOUD , 'background': None, 'font':FONTITAL},
'KEYWORD' : {'foreground': DK_SEAFOAM, 'background': None, 'font':FONTBOLD},
'CLASSDEF' : {'foreground': PURPLE , 'background': None, 'font':FONTBOLD},
}
'''
#what literally happens to this data when it is applied
for tag, cfg in self.tagdefs.items():
self.tag_configure(tag, **cfg)
'''
一旦完成设置,您就可以轻松插入所有内容。如果您制作自定义文本小部件,您可以将以下内容放入
__init__
中,并将 YourTextWidget
更改为 self
。否则,只需将 YourTextWidget
更改为您想要连接到的文本小部件的实例名称(如 tfpf 的答案 中所示)。
cd = ic.ColorDelegator()
cd.prog = re.compile(PROG, re.S|re.M)
cd.idprog = re.compile(IDPROG, re.S)
cd.tagdefs = {**cd.tagdefs, **TAGDEFS}
ip.Percolator(YourTextWidget).insertfilter(cd)
cd.tagdefs = {**cd.tagdefs, **TAGDEFS}
我为什么要这么做?我们不会使用此方法省略任何值。如果
KEYWORD
在 tagdefs
中定义,但不在 TAGDEFS
中怎么办?如果我们不首先将 tagdefs
解压到自身中,我们就会丢失 KEYWORD
。
总结系统的这一端:运行一个大的正则表达式,无论
regex group
名称匹配,都会成为要应用的标签的名称。无论您创建什么新的 regex groups
都应该(也许必须)在 .tagdefs
中具有相同名称的密钥。
这是igwd 的回答的后续内容。
idlelib.colorizer.ColorDelegator
和idlelib.percolator.Percolator
似乎没有很好地记录,所以我决定发布我发现的内容。
如果您希望突出显示“tkinter”和“in”等单词,您可能需要普通的 Python 语法突出显示和一些附加内容。
import idlelib.colorizer as ic
import idlelib.percolator as ip
import re
import tkinter as tk
root = tk.Tk()
root.title('Python Syntax Highlighting')
text = tk.Text(root)
text.pack()
cdg = ic.ColorDelegator()
cdg.prog = re.compile(r'\b(?P<MYGROUP>tkinter)\b|' + ic.make_pat(), re.S)
cdg.idprog = re.compile(r'\s+(\w+)', re.S)
cdg.tagdefs['MYGROUP'] = {'foreground': '#7F7F7F', 'background': '#FFFFFF'}
# These five lines are optional. If omitted, default colours are used.
cdg.tagdefs['COMMENT'] = {'foreground': '#FF0000', 'background': '#FFFFFF'}
cdg.tagdefs['KEYWORD'] = {'foreground': '#007F00', 'background': '#FFFFFF'}
cdg.tagdefs['BUILTIN'] = {'foreground': '#7F7F00', 'background': '#FFFFFF'}
cdg.tagdefs['STRING'] = {'foreground': '#7F3F00', 'background': '#FFFFFF'}
cdg.tagdefs['DEFINITION'] = {'foreground': '#007F7F', 'background': '#FFFFFF'}
ip.Percolator(text).insertfilter(cdg)
root.mainloop()
上述 MWE 适用于 Python 3.8。在 Python 3.10 上,只需将
cdg.prog = re.compile(r'\b(?P<MYGROUP>tkinter)\b|' + ic.make_pat(), re.S)
替换为 cdg.prog = re.compile(r'\b(?P<MYGROUP>tkinter)\b|' + ic.make_pat().pattern, re.S)
。我还没有用其他 Python 版本测试过这个。
这些代码可以在IDLE中实现语法高亮。 您可以复制源代码并修改某些内容。
import tkinter as tk
from idlelib.percolator import Percolator
from idlelib.colorizer import ColorDelegator
main = tk.Tk()
text = tk.Text(main)
text.pack()
Percolator(text).insertfilter(ColorDelegator())
main.mainloop()
使用标签。我将实施那里给出的概念。
示例:
import tkinter as tk
root = tk.Tk()
root.title("Begueradj")
text = tk.Text(root)
# Insert some text
text.insert(tk.INSERT, "Security ")
text.insert(tk.END, " Pentesting ")
text.insert(tk.END, "Hacking ")
text.insert(tk.END, "Coding")
text.pack()
# Create some tags
text.tag_add("one", "1.0", "1.8")
text.tag_add("two", "1.10", "1.20")
text.tag_add("three", "1.21", "1.28")
text.tag_add("four", "1.29", "1.36")
#Configure the tags
text.tag_config("one", background="yellow", foreground="blue")
text.tag_config("two", background="black", foreground="green")
text.tag_config("three", background="blue", foreground="yellow")
text.tag_config("four", background="red", foreground="black")
#Start the program
root.mainloop()
演示:
选项:
pygments示例:here其中使用 get_style_by_name("default").list_styles() 作为内置样式;将 lexer 替换为 PythonLexer for Python
idlelib示例:
from tkinter import Tk
from tkinter import Text
from idlelib.colorizer import ColorDelegator, color_config
from idlelib.percolator import Percolator
from idlelib.undo import UndoDelegator
class CustomEditor:
def __init__(self):
self.root = Tk()
self.text = text = Text(self.root)
text.pack()
self.perc = perc = Percolator(text)
self.undo = undo = UndoDelegator()
perc.insertfilter(undo)
self.color = None
self.code_context = None
self.ResetColorizer()
def _add_colorizer(self):
if self.color:
return
self.color = ColorDelegator()
self.perc.insertfilterafter(filter=self.color, after=self.undo)
def _rm_colorizer(self):
if not self.color:
return
self.color.removecolors()
self.perc.removefilter(self.color)
self.color = None
def ResetColorizer(self):
self._rm_colorizer()
self._add_colorizer()
color_config(self.text)
editor = CustomEditor()
editor.text.insert(1.0, "print('Hello')\n")
editor.text.focus_set()
editor.root.mainloop()