如何获取当前行的行索引
How to get the line index of the current line
我正在使用从 YouTube 教程获得的基础制作测试编辑器。
我试图突出显示 python 的语句,但是当我写一个语句时,它使所有行都变色了,我认为问题出在我创建的索引的使用上。
这是代码:
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
class Menubar:
def __init__(self, parent):
font_specs = 14
menubar = tk.Menu(parent.master)
parent.master.config(menu = menubar)
file_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
file_dropdown.add_command(label = "Nuovo file",
accelerator = "Ctrl + N",
command = parent.new_file)
file_dropdown.add_command(label = "Apri file",
accelerator = "Ctrl + O",
command = parent.open_file)
file_dropdown.add_command(label = "Salva",
accelerator = "Ctrl + S",
command = parent.save)
file_dropdown.add_command(label = "Salva con nome",
accelerator = "Ctrl + Shit + S",
command = parent.save_as)
file_dropdown.add_separator()
file_dropdown.add_command(label = "Esci",
command = parent.master.destroy)
about_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
about_dropdown.add_command(label = "Note di rilascio",
command = self.show_about_message)
about_dropdown.add_separator()
about_dropdown.add_command(label = "About",
command = self.show_release_notes)
settings_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
settings_dropdown.add_command(label = "Cambia lo sfondo dell'editor",
command = parent.change_background)
menubar.add_cascade(label = "File", menu = file_dropdown)
menubar.add_cascade(label = "About", menu = about_dropdown)
menubar.add_cascade(label = "Settings", menu = settings_dropdown)
def show_about_message(self):
box_title = "Riguardo PyText"
box_message = "Il mio primo editor testuale creato con Python e TkInter!"
messagebox.showinfo(box_title, box_message)
def show_release_notes(self):
box_title = "Note di Rilascio"
box_message = "Versione 0.1 (Beta) Santa"
messagebox.showinfo(box_title, box_message)
class Statusbar:
def __init__(self, parent):
font_specs = 12
self.status = tk.StringVar()
self.status.set("PyText - 0.1 Santa")
label = tk.Label(parent.text_area, textvariable = self.status,
fg = "black", bg = "lightgrey", anchor = "sw")
label.pack(side = tk.BOTTOM, fill = tk.BOTH)
def update_status(self, *args):
if isinstance(args[0], bool):
self.status.set("Il tuo file è stato salvato!")
else:
self.status.set("PyText - 0.1 Santa")
class PyText:
"""
Classe-Madre dell'applicazione
"""
def __init__(self, master):
master.title("Untitled - PyText")
master.geometry("1200x700")
font_specs = 18
self.master = master
self.filename = None
self.text_area = tk.Text(master, font = font_specs, insertbackground = "black")
self.scroll = tk.Scrollbar(master, command = self.text_area.yview)
self.text_area.configure(yscrollcommand = self.scroll.set)
self.text_area.pack(side = tk.LEFT, fill = tk.BOTH, expand = True)
self.scroll.pack(side = tk.RIGHT, fill = tk.Y)
self.menubar = Menubar(self)
self.statusbar = Statusbar(self)
self.bind_shortcuts()
def set_window_title(self, name = None):
if name:
self.master.title(name + " - PyText")
else:
self.master.title("Untitled - PyText")
def new_file(self, *args):
self.text_area.delete(1.0, tk.END)
self.filename = None
self.set_window_title()
def open_file(self, *args):
self.filename = filedialog.askopenfilename(
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
if self.filename:
self.text_area.delete(1.0, tk.END)
with open(self.filename, "r") as f:
self.text_area.insert(1.0, f.read())
self.set_window_title(self.filename)
def save(self, *args):
if self.filename:
try:
textarea_content = self.text_area.get(1.0, tk.END)
with open(self.filename, "w") as f:
f.write(textarea_content)
self.statusbar.update_status(True)
except Exception as e:
print(e)
else:
self.save_as()
def save_as(self, *args):
try:
new_file = filedialog.asksaveasfilename(
initialfile = "Untitled.txt",
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
textarea_content = self.text_area.get(1.0, tk.END)
with open(new_file, "w") as f:
f.write(textarea_content)
self.filename = new_file
self.set_window_title(self.filename)
self.statusbar.update_status(True)
except Exception as e:
print(e)
def change_background(self):
self.text_area.config(background = "black", foreground = "white",
insertbackground = "white", insertwidth = 2)
def highlight_text(self, *args):
tags = {
"import": "pink",
"from": "pink",
"def": "blue",
"for": "purple",
"while": "purple"
}
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for row in lines:
for tag in tags:
index = row.find(tag) + 1.0
if index > 0.0:
self.text_area.tag_add(tag, index, index + len(tag) -1)
self.text_area.tag_config(tag, foreground = tags.get(tag))
print("Nuovo tag aggiunto:", tag)
print("Funzione eseguita:", args, "\n")
def bind_shortcuts(self):
self.text_area.bind("<Control-n>", self.new_file)
self.text_area.bind("<Control-o>", self.open_file)
self.text_area.bind("<Control-s>", self.save)
self.text_area.bind("<Control-S>", self.save_as)
self.text_area.bind("<Key>", self.highlight_text, self.statusbar.update_status)
if __name__ == "__main__":
master = tk.Tk()
pt = PyText(master)
master.mainloop()
如何获取语句所在行的索引?
你单独处理每一行,所以你只得到 X
。要获得 Y
,您需要 enumerate
行:
for y, row in enumerate(lines, 1):
来自 find()
的结果你转换为 float
但你需要 int
然后将 X,Y
转换为字符串 "Y.X"
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
适合我的版本
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {start} | end: {end}")
self.text_area.tag_add(tag, start, end)
self.text_area.tag_config(tag, foreground = tags.get(tag))
你的想法只有一个大问题 - 它会在单词 define
中着色 def
,或者在单词 forward
中着色 for
,等等。所以也许它需要regex
创建更复杂的规则并只搜索完整的单词。
其他问题:find()
只给你行中的第一个项目 - 所以如果你想突出显示行中可能两次的元素,那么你将不得不使用 find(..., start)
的循环来搜索第一个元素。
也许使用 How to highlight text in a tkinter Text widget
的例子会更好
顺便说一句:
您将快捷键绑定到 self.text_area
,所以我必须单击文本区域才能使用快捷键。如果我将 self.text_area.bind
更改为 self.master.bind
,那么即使不单击文本区域,快捷方式也能正常工作。
编辑:
有 Thonny IDE 使用 Tkinter
并突出显示代码。
我试图找出它是如何做到这一点的,但我只找到了高亮显示的正则表达式 - thonny_utils.py
也许如果你得到完整的代码并使用一些工具在文件中搜索字符串(比如 Linux 中的 grep
)那么你可以找到它使用来自 token_utils.py
的变量的所有地方(即 KEYWORD
)
编辑: coloring.py
编辑:
具有函数 highlight_text
的完整代码,它使用以前的方法 line.find
和 highlight_text_regex
,它使用 text_area.search
和 regex
。
基于问题答案代码的新版本How to highlight text in a tkinter Text widget
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import os
print(os.getcwd())
class Menubar:
def __init__(self, parent):
font_specs = 14
menubar = tk.Menu(parent.master)
parent.master.config(menu = menubar)
file_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
file_dropdown.add_command(label = "Nuovo file",
accelerator = "Ctrl + N",
command = parent.new_file)
file_dropdown.add_command(label = "Apri file",
accelerator = "Ctrl + O",
command = parent.open_file)
file_dropdown.add_command(label = "Salva",
accelerator = "Ctrl + S",
command = parent.save)
file_dropdown.add_command(label = "Salva con nome",
accelerator = "Ctrl + Shift + S",
command = parent.save_as)
file_dropdown.add_separator()
file_dropdown.add_command(label = "Esci",
accelerator = "Ctrl + Q",
command = parent.master.destroy)
about_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
about_dropdown.add_command(label = "Note di rilascio",
command = self.show_about_message)
about_dropdown.add_separator()
about_dropdown.add_command(label = "About",
command = self.show_release_notes)
settings_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
settings_dropdown.add_command(label = "Cambia lo sfondo dell'editor",
command = parent.change_background)
menubar.add_cascade(label = "File", menu = file_dropdown)
menubar.add_cascade(label = "About", menu = about_dropdown)
menubar.add_cascade(label = "Settings", menu = settings_dropdown)
def show_about_message(self):
box_title = "Riguardo PyText"
box_message = "Il mio primo editor testuale creato con Python e TkInter!"
messagebox.showinfo(box_title, box_message)
def show_release_notes(self):
box_title = "Note di Rilascio"
box_message = "Versione 0.1 (Beta) Santa"
messagebox.showinfo(box_title, box_message)
class Statusbar:
def __init__(self, parent):
font_specs = 12
self.status = tk.StringVar()
self.status.set("PyText - 0.1 Santa")
label = tk.Label(parent.text_area, textvariable = self.status,
fg = "black", bg = "lightgrey", anchor = "sw")
label.pack(side = tk.BOTTOM, fill = tk.BOTH)
def update_status(self, *args):
if isinstance(args[0], bool):
self.status.set("Il tuo file è stato salvato!")
else:
self.status.set("PyText - 0.1 Santa")
class PyText:
"""
Classe-Madre dell'applicazione
"""
def __init__(self, master):
master.title("Untitled - PyText")
master.geometry("1200x700")
font_specs = 18
self.master = master
self.filename = None
self.text_area = tk.Text(master, font = font_specs, insertbackground = "black")
self.scroll = tk.Scrollbar(master, command = self.text_area.yview)
self.text_area.configure(yscrollcommand = self.scroll.set)
self.text_area.pack(side = tk.LEFT, fill = tk.BOTH, expand = True)
self.scroll.pack(side = tk.RIGHT, fill = tk.Y)
self.menubar = Menubar(self)
self.statusbar = Statusbar(self)
self.bind_shortcuts()
def set_window_title(self, name = None):
if name:
self.master.title(name + " - PyText")
else:
self.master.title("Untitled - PyText")
def new_file(self, *args):
self.text_area.delete(1.0, tk.END)
self.filename = None
self.set_window_title()
def open_file(self, *args):
self.filename = filedialog.askopenfilename(
initialdir = os.getcwd(),
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
if self.filename:
self.text_area.delete(1.0, tk.END)
with open(self.filename, "r") as f:
self.text_area.insert(1.0, f.read())
self.set_window_title(self.filename)
def save(self, *args):
if self.filename:
try:
textarea_content = self.text_area.get(1.0, tk.END)
with open(self.filename, "w") as f:
f.write(textarea_content)
self.statusbar.update_status(True)
except Exception as e:
print(e)
else:
self.save_as()
def save_as(self, *args):
try:
new_file = filedialog.asksaveasfilename(
initialfile = "Untitled.txt",
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
textarea_content = self.text_area.get(1.0, tk.END)
with open(new_file, "w") as f:
f.write(textarea_content)
self.filename = new_file
self.set_window_title(self.filename)
self.statusbar.update_status(True)
except Exception as e:
print(e)
def change_background(self):
self.text_area.config(background = "black", foreground = "white",
insertbackground = "white", insertwidth = 2)
def highlight_text_old(self, *args):
tags = {
"import": "pink",
"from": "red",
"def": "blue",
"for": "purple",
"while": "green",
}
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {start} | end: {end}")
self.text_area.tag_add(tag, start, end)
self.text_area.tag_config(tag, foreground = tags.get(tag))
#print("Nuovo tag aggiunto:", tag)
#print("Funzione eseguita:", args, "\n")
def highlight_text(self, *args):
# TODO: move to `__init__` ?
tags = {
"import": "pink",
"from": "red",
"def": "blue",
"for": "purple",
"while": "green",
}
# TODO: move to `__init__` ?
# create tags with assigned color - do it only onve (in __init__)
for color in ['pink', 'red', 'blue', 'purple', 'green']:
self.text_area.tag_config(color, foreground=color)
# remove all tags from text
for tag in self.text_area.tag_names():
self.text_area.tag_remove(tag, '1.0', 'end') # not `tag_remove()`
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
match_start = '{}.{}'.format(y, x)
match_end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {match_start} | end: {match_end}")
self.text_area.tag_add(tag, match_start, match_end)
#self.text_area.tag_config(tag, foreground=tags.get(tag)) # create tags only once - at start
#print("Nuovo tag aggiunto:", tag)
#print("Funzione eseguita:", args, "\n")
def highlight_text_regex(self, *args):
# TODO: move to `__init__` ?
tags = {
"import": "red",
"from": "red",
"as": "red",
"def": "blue",
"class": "blue",
"for": "green",
"while": "green",
"if": "brown",
"elif": "brown",
"else": "brown",
"print": "purple",
"True": "blue",
"False": "blue",
"self": "blue",
"\d+": "red", # digits
"__[a-zA-Z][a-zA-Z0-9_]*__": "red", # ie. `__init__`
}
# add `\m \M` to words
tags = {f'\m{word}\M': tag for word, tag in tags.items()}
# tags which doesn't work with `\m \M`
other_tags = {
"\(": "brown", # need `\` because `(` has special meaning
"\)": "brown", # need `\` because `)` has special meaning
">=": "green",
"<=": "green",
"=": "green",
">": "green",
"<": "green",
"#.*$": "brown", # comment - to the end of line `$`
}
# create one dictionary with all tags
tags.update(other_tags)
# TODO: move to `__init__` ?
# create tags with assigned color - do it only onve (in __init__)
for color in ['pink', 'red', 'blue', 'purple', 'green', 'brown', 'yellow']:
self.text_area.tag_config(color, foreground=color)
# remove all tags from text before adding all tags again (to change color when ie. `def` change to `define`)
for tag in self.text_area.tag_names():
self.text_area.tag_remove(tag, '1.0', 'end') # not `tag_remove()`
count_chars = tk.IntVar() # needs to count matched chars - ie. for digits `\d+`
# search `word` and add `tag`
for word, tag in tags.items():
#pattern = f'\m{word}\M' # http://tcl.tk/man/tcl8.5/TclCmd/re_syntax.htm#M72
pattern = word # http://tcl.tk/man/tcl8.5/TclCmd/re_syntax.htm#M72
search_start = '1.0'
search_end = 'end'
while True:
position = self.text_area.search(pattern, search_start, search_end, count=count_chars, regexp=True)
print('search:', word, position)
if position:
print(f"{word} | pos: {position}")
match_start = position
match_end = '{}+{}c'.format(position, count_chars.get()) #len(word)) # use special string `Y.X+Nc` instead values (Y, X+N)
print(f"{word} | start: {match_start} | end: {match_end}")
self.text_area.tag_add(tag, match_start, match_end)
#self.text_area.tag_config(tag, foreground=tags.get(tag)) # create tags only once - at start
search_start = match_end # to search next word
else:
break
def quit(self, *args):
self.master.destroy()
def bind_shortcuts(self):
self.master.bind("<Control-n>", self.new_file)
self.master.bind("<Control-o>", self.open_file)
self.master.bind("<Control-s>", self.save)
self.master.bind("<Control-S>", self.save_as)
self.master.bind("<Control-q>", self.quit)
self.master.bind("<Key>", self.highlight_text_regex, self.statusbar.update_status)
if __name__ == "__main__":
master = tk.Tk()
pt = PyText(master)
master.mainloop()
我正在使用从 YouTube 教程获得的基础制作测试编辑器。 我试图突出显示 python 的语句,但是当我写一个语句时,它使所有行都变色了,我认为问题出在我创建的索引的使用上。
这是代码:
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
class Menubar:
def __init__(self, parent):
font_specs = 14
menubar = tk.Menu(parent.master)
parent.master.config(menu = menubar)
file_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
file_dropdown.add_command(label = "Nuovo file",
accelerator = "Ctrl + N",
command = parent.new_file)
file_dropdown.add_command(label = "Apri file",
accelerator = "Ctrl + O",
command = parent.open_file)
file_dropdown.add_command(label = "Salva",
accelerator = "Ctrl + S",
command = parent.save)
file_dropdown.add_command(label = "Salva con nome",
accelerator = "Ctrl + Shit + S",
command = parent.save_as)
file_dropdown.add_separator()
file_dropdown.add_command(label = "Esci",
command = parent.master.destroy)
about_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
about_dropdown.add_command(label = "Note di rilascio",
command = self.show_about_message)
about_dropdown.add_separator()
about_dropdown.add_command(label = "About",
command = self.show_release_notes)
settings_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
settings_dropdown.add_command(label = "Cambia lo sfondo dell'editor",
command = parent.change_background)
menubar.add_cascade(label = "File", menu = file_dropdown)
menubar.add_cascade(label = "About", menu = about_dropdown)
menubar.add_cascade(label = "Settings", menu = settings_dropdown)
def show_about_message(self):
box_title = "Riguardo PyText"
box_message = "Il mio primo editor testuale creato con Python e TkInter!"
messagebox.showinfo(box_title, box_message)
def show_release_notes(self):
box_title = "Note di Rilascio"
box_message = "Versione 0.1 (Beta) Santa"
messagebox.showinfo(box_title, box_message)
class Statusbar:
def __init__(self, parent):
font_specs = 12
self.status = tk.StringVar()
self.status.set("PyText - 0.1 Santa")
label = tk.Label(parent.text_area, textvariable = self.status,
fg = "black", bg = "lightgrey", anchor = "sw")
label.pack(side = tk.BOTTOM, fill = tk.BOTH)
def update_status(self, *args):
if isinstance(args[0], bool):
self.status.set("Il tuo file è stato salvato!")
else:
self.status.set("PyText - 0.1 Santa")
class PyText:
"""
Classe-Madre dell'applicazione
"""
def __init__(self, master):
master.title("Untitled - PyText")
master.geometry("1200x700")
font_specs = 18
self.master = master
self.filename = None
self.text_area = tk.Text(master, font = font_specs, insertbackground = "black")
self.scroll = tk.Scrollbar(master, command = self.text_area.yview)
self.text_area.configure(yscrollcommand = self.scroll.set)
self.text_area.pack(side = tk.LEFT, fill = tk.BOTH, expand = True)
self.scroll.pack(side = tk.RIGHT, fill = tk.Y)
self.menubar = Menubar(self)
self.statusbar = Statusbar(self)
self.bind_shortcuts()
def set_window_title(self, name = None):
if name:
self.master.title(name + " - PyText")
else:
self.master.title("Untitled - PyText")
def new_file(self, *args):
self.text_area.delete(1.0, tk.END)
self.filename = None
self.set_window_title()
def open_file(self, *args):
self.filename = filedialog.askopenfilename(
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
if self.filename:
self.text_area.delete(1.0, tk.END)
with open(self.filename, "r") as f:
self.text_area.insert(1.0, f.read())
self.set_window_title(self.filename)
def save(self, *args):
if self.filename:
try:
textarea_content = self.text_area.get(1.0, tk.END)
with open(self.filename, "w") as f:
f.write(textarea_content)
self.statusbar.update_status(True)
except Exception as e:
print(e)
else:
self.save_as()
def save_as(self, *args):
try:
new_file = filedialog.asksaveasfilename(
initialfile = "Untitled.txt",
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
textarea_content = self.text_area.get(1.0, tk.END)
with open(new_file, "w") as f:
f.write(textarea_content)
self.filename = new_file
self.set_window_title(self.filename)
self.statusbar.update_status(True)
except Exception as e:
print(e)
def change_background(self):
self.text_area.config(background = "black", foreground = "white",
insertbackground = "white", insertwidth = 2)
def highlight_text(self, *args):
tags = {
"import": "pink",
"from": "pink",
"def": "blue",
"for": "purple",
"while": "purple"
}
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for row in lines:
for tag in tags:
index = row.find(tag) + 1.0
if index > 0.0:
self.text_area.tag_add(tag, index, index + len(tag) -1)
self.text_area.tag_config(tag, foreground = tags.get(tag))
print("Nuovo tag aggiunto:", tag)
print("Funzione eseguita:", args, "\n")
def bind_shortcuts(self):
self.text_area.bind("<Control-n>", self.new_file)
self.text_area.bind("<Control-o>", self.open_file)
self.text_area.bind("<Control-s>", self.save)
self.text_area.bind("<Control-S>", self.save_as)
self.text_area.bind("<Key>", self.highlight_text, self.statusbar.update_status)
if __name__ == "__main__":
master = tk.Tk()
pt = PyText(master)
master.mainloop()
如何获取语句所在行的索引?
你单独处理每一行,所以你只得到 X
。要获得 Y
,您需要 enumerate
行:
for y, row in enumerate(lines, 1):
来自 find()
的结果你转换为 float
但你需要 int
然后将 X,Y
转换为字符串 "Y.X"
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
适合我的版本
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {start} | end: {end}")
self.text_area.tag_add(tag, start, end)
self.text_area.tag_config(tag, foreground = tags.get(tag))
你的想法只有一个大问题 - 它会在单词 define
中着色 def
,或者在单词 forward
中着色 for
,等等。所以也许它需要regex
创建更复杂的规则并只搜索完整的单词。
其他问题:find()
只给你行中的第一个项目 - 所以如果你想突出显示行中可能两次的元素,那么你将不得不使用 find(..., start)
的循环来搜索第一个元素。
也许使用 How to highlight text in a tkinter Text widget
的例子会更好顺便说一句:
您将快捷键绑定到 self.text_area
,所以我必须单击文本区域才能使用快捷键。如果我将 self.text_area.bind
更改为 self.master.bind
,那么即使不单击文本区域,快捷方式也能正常工作。
编辑:
有 Thonny IDE 使用 Tkinter
并突出显示代码。
我试图找出它是如何做到这一点的,但我只找到了高亮显示的正则表达式 - thonny_utils.py
也许如果你得到完整的代码并使用一些工具在文件中搜索字符串(比如 Linux 中的 grep
)那么你可以找到它使用来自 token_utils.py
的变量的所有地方(即 KEYWORD
)
编辑: coloring.py
编辑:
具有函数 highlight_text
的完整代码,它使用以前的方法 line.find
和 highlight_text_regex
,它使用 text_area.search
和 regex
。
基于问题答案代码的新版本How to highlight text in a tkinter Text widget
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import os
print(os.getcwd())
class Menubar:
def __init__(self, parent):
font_specs = 14
menubar = tk.Menu(parent.master)
parent.master.config(menu = menubar)
file_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
file_dropdown.add_command(label = "Nuovo file",
accelerator = "Ctrl + N",
command = parent.new_file)
file_dropdown.add_command(label = "Apri file",
accelerator = "Ctrl + O",
command = parent.open_file)
file_dropdown.add_command(label = "Salva",
accelerator = "Ctrl + S",
command = parent.save)
file_dropdown.add_command(label = "Salva con nome",
accelerator = "Ctrl + Shift + S",
command = parent.save_as)
file_dropdown.add_separator()
file_dropdown.add_command(label = "Esci",
accelerator = "Ctrl + Q",
command = parent.master.destroy)
about_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
about_dropdown.add_command(label = "Note di rilascio",
command = self.show_about_message)
about_dropdown.add_separator()
about_dropdown.add_command(label = "About",
command = self.show_release_notes)
settings_dropdown = tk.Menu(menubar, font = font_specs, tearoff = 0)
settings_dropdown.add_command(label = "Cambia lo sfondo dell'editor",
command = parent.change_background)
menubar.add_cascade(label = "File", menu = file_dropdown)
menubar.add_cascade(label = "About", menu = about_dropdown)
menubar.add_cascade(label = "Settings", menu = settings_dropdown)
def show_about_message(self):
box_title = "Riguardo PyText"
box_message = "Il mio primo editor testuale creato con Python e TkInter!"
messagebox.showinfo(box_title, box_message)
def show_release_notes(self):
box_title = "Note di Rilascio"
box_message = "Versione 0.1 (Beta) Santa"
messagebox.showinfo(box_title, box_message)
class Statusbar:
def __init__(self, parent):
font_specs = 12
self.status = tk.StringVar()
self.status.set("PyText - 0.1 Santa")
label = tk.Label(parent.text_area, textvariable = self.status,
fg = "black", bg = "lightgrey", anchor = "sw")
label.pack(side = tk.BOTTOM, fill = tk.BOTH)
def update_status(self, *args):
if isinstance(args[0], bool):
self.status.set("Il tuo file è stato salvato!")
else:
self.status.set("PyText - 0.1 Santa")
class PyText:
"""
Classe-Madre dell'applicazione
"""
def __init__(self, master):
master.title("Untitled - PyText")
master.geometry("1200x700")
font_specs = 18
self.master = master
self.filename = None
self.text_area = tk.Text(master, font = font_specs, insertbackground = "black")
self.scroll = tk.Scrollbar(master, command = self.text_area.yview)
self.text_area.configure(yscrollcommand = self.scroll.set)
self.text_area.pack(side = tk.LEFT, fill = tk.BOTH, expand = True)
self.scroll.pack(side = tk.RIGHT, fill = tk.Y)
self.menubar = Menubar(self)
self.statusbar = Statusbar(self)
self.bind_shortcuts()
def set_window_title(self, name = None):
if name:
self.master.title(name + " - PyText")
else:
self.master.title("Untitled - PyText")
def new_file(self, *args):
self.text_area.delete(1.0, tk.END)
self.filename = None
self.set_window_title()
def open_file(self, *args):
self.filename = filedialog.askopenfilename(
initialdir = os.getcwd(),
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
if self.filename:
self.text_area.delete(1.0, tk.END)
with open(self.filename, "r") as f:
self.text_area.insert(1.0, f.read())
self.set_window_title(self.filename)
def save(self, *args):
if self.filename:
try:
textarea_content = self.text_area.get(1.0, tk.END)
with open(self.filename, "w") as f:
f.write(textarea_content)
self.statusbar.update_status(True)
except Exception as e:
print(e)
else:
self.save_as()
def save_as(self, *args):
try:
new_file = filedialog.asksaveasfilename(
initialfile = "Untitled.txt",
defaultextension = ".txt",
filetypes = [("Tutti i file", "*.*"),
("File di Testo", "*.txt"),
("Script Python", "*.py"),
("Markdown Text", "*.md"),
("File JavaScript", "*.js"),
("Documenti Html", "*.html"),
("Documenti CSS", "*.css"),
("Programmi Java", "*.java")]
)
textarea_content = self.text_area.get(1.0, tk.END)
with open(new_file, "w") as f:
f.write(textarea_content)
self.filename = new_file
self.set_window_title(self.filename)
self.statusbar.update_status(True)
except Exception as e:
print(e)
def change_background(self):
self.text_area.config(background = "black", foreground = "white",
insertbackground = "white", insertwidth = 2)
def highlight_text_old(self, *args):
tags = {
"import": "pink",
"from": "red",
"def": "blue",
"for": "purple",
"while": "green",
}
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
start = '{}.{}'.format(y, x)
end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {start} | end: {end}")
self.text_area.tag_add(tag, start, end)
self.text_area.tag_config(tag, foreground = tags.get(tag))
#print("Nuovo tag aggiunto:", tag)
#print("Funzione eseguita:", args, "\n")
def highlight_text(self, *args):
# TODO: move to `__init__` ?
tags = {
"import": "pink",
"from": "red",
"def": "blue",
"for": "purple",
"while": "green",
}
# TODO: move to `__init__` ?
# create tags with assigned color - do it only onve (in __init__)
for color in ['pink', 'red', 'blue', 'purple', 'green']:
self.text_area.tag_config(color, foreground=color)
# remove all tags from text
for tag in self.text_area.tag_names():
self.text_area.tag_remove(tag, '1.0', 'end') # not `tag_remove()`
textarea_content = self.text_area.get(1.0, tk.END)
lines = textarea_content.split("\n")
for y, row in enumerate(lines, 1):
for tag in tags:
x = row.find(tag)
if x > -1:
print(f"{tag} | x: {x} | y: {y}")
match_start = '{}.{}'.format(y, x)
match_end = '{}.{}'.format(y, x+len(tag))
print(f"{tag} | start: {match_start} | end: {match_end}")
self.text_area.tag_add(tag, match_start, match_end)
#self.text_area.tag_config(tag, foreground=tags.get(tag)) # create tags only once - at start
#print("Nuovo tag aggiunto:", tag)
#print("Funzione eseguita:", args, "\n")
def highlight_text_regex(self, *args):
# TODO: move to `__init__` ?
tags = {
"import": "red",
"from": "red",
"as": "red",
"def": "blue",
"class": "blue",
"for": "green",
"while": "green",
"if": "brown",
"elif": "brown",
"else": "brown",
"print": "purple",
"True": "blue",
"False": "blue",
"self": "blue",
"\d+": "red", # digits
"__[a-zA-Z][a-zA-Z0-9_]*__": "red", # ie. `__init__`
}
# add `\m \M` to words
tags = {f'\m{word}\M': tag for word, tag in tags.items()}
# tags which doesn't work with `\m \M`
other_tags = {
"\(": "brown", # need `\` because `(` has special meaning
"\)": "brown", # need `\` because `)` has special meaning
">=": "green",
"<=": "green",
"=": "green",
">": "green",
"<": "green",
"#.*$": "brown", # comment - to the end of line `$`
}
# create one dictionary with all tags
tags.update(other_tags)
# TODO: move to `__init__` ?
# create tags with assigned color - do it only onve (in __init__)
for color in ['pink', 'red', 'blue', 'purple', 'green', 'brown', 'yellow']:
self.text_area.tag_config(color, foreground=color)
# remove all tags from text before adding all tags again (to change color when ie. `def` change to `define`)
for tag in self.text_area.tag_names():
self.text_area.tag_remove(tag, '1.0', 'end') # not `tag_remove()`
count_chars = tk.IntVar() # needs to count matched chars - ie. for digits `\d+`
# search `word` and add `tag`
for word, tag in tags.items():
#pattern = f'\m{word}\M' # http://tcl.tk/man/tcl8.5/TclCmd/re_syntax.htm#M72
pattern = word # http://tcl.tk/man/tcl8.5/TclCmd/re_syntax.htm#M72
search_start = '1.0'
search_end = 'end'
while True:
position = self.text_area.search(pattern, search_start, search_end, count=count_chars, regexp=True)
print('search:', word, position)
if position:
print(f"{word} | pos: {position}")
match_start = position
match_end = '{}+{}c'.format(position, count_chars.get()) #len(word)) # use special string `Y.X+Nc` instead values (Y, X+N)
print(f"{word} | start: {match_start} | end: {match_end}")
self.text_area.tag_add(tag, match_start, match_end)
#self.text_area.tag_config(tag, foreground=tags.get(tag)) # create tags only once - at start
search_start = match_end # to search next word
else:
break
def quit(self, *args):
self.master.destroy()
def bind_shortcuts(self):
self.master.bind("<Control-n>", self.new_file)
self.master.bind("<Control-o>", self.open_file)
self.master.bind("<Control-s>", self.save)
self.master.bind("<Control-S>", self.save_as)
self.master.bind("<Control-q>", self.quit)
self.master.bind("<Key>", self.highlight_text_regex, self.statusbar.update_status)
if __name__ == "__main__":
master = tk.Tk()
pt = PyText(master)
master.mainloop()