I'm making a Test Editor from a base that I got from a YouTube tutorial. I was trying to make highlighted the python's statements, but when I write a statement, it colorizes all the lines, and I thought that the problem is the use of indexes I make.
This is the code:
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()
How can I get the index of the line where is the statement?
You works with every line separtelly so you get only
X
. To getY
you need toenumerate
lines:Result from
find()
you convert tofloat
but you needint
and later convertX,Y
to string"Y.X"
Version which works for me
Your idea has only one big problem - it will colorize
def
in worddefine
, orfor
in wordforward
, etc. So maybe it would needregex
to create more complex rules and search only full words.Other problem:
find()
gives you only first item in line - so if you will try to highlight element which can be two times in line then you would have to use loop withfind(..., start)
to search after first element.Maybe it would be better to use example for How to highlight text in a tkinter Text widget
BTW:
You binded key shortcuts to
self.text_area
so I had to click in text area to use shortcut. If I changeself.text_area.bind
intoself.master.bind
then shortcuts works even without clicking in text area.EDIT:
There is Thonny IDE which uses
Tkinter
and it highlights code.I tried to find how it makes this but I found only regex for highlights - thonny_utils.py
Maybe if you get full code and use some tool to search string in files (like
grep
in Linux) then you could find all places where it uses variables fromtoken_utils.py
(ie.KEYWORD
)EDIT: coloring.py
EDIT:
Full code with function
highlight_text
which uses previous methodline.find
andhighlight_text_regex
which usestext_area.search
withregex
.New version based on code from answer to question How to highlight text in a tkinter Text widget