If you’ve worked with tkinter’s Text widget, you may notice that when you add many tags to it sometimes things get messed. So let’s dive right into this. We will use syntax highlighting as an example.
Explaining our goal
Consider we have the following code,
from tkinter import * class Files(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.pack(fill=BOTH, expand=1) self.txt = Text(self) self.txt.pack(fill=BOTH, expand=1) root = Tk() top = Frame(root) top.pack(fill=BOTH, expand=0) bottom = Frame(root) bottom.pack() ex = Files(root) ex.pack(side="bottom") root.geometry("600x500-600-150") root.mainloop()
which gives us a simple Text widget.


Let’s say we want to highlight some specific words. And let’s do it every time a user enters something.
We will be highlighting word “Hello” with red and “world” with blue. So all we must do is make a function that will run every time a key is pressed and will highlight the words.
[...] def initUI(self): self.pack(fill=BOTH, expand=1) self.bind_all("<Key>", self.highlight) #this runs 'highlight' function every time a key is pressed self.txt = Text(self) self.txt.pack(fill=BOTH, expand=1) def highlight(self, event=0): file_text = self.txt.get("1.0", END+"-1c") + " " #a blank space at the end is for easier separating words words = [] #we will store words along with their starting point line = 1 #} column = -1 #}these are starting points that will help us in the following 'for' loop word = "" #} #now we have to find words and assign them their line and column for char in file_text: word += char column += 1 if char == "\n": #here a word stops words.append(word[:-1] + " : " + str(line) + "." + str(column)) word = "" line += 1 column = -1 if char == " ": #here a word stops words.append(word[:-1] + " : " + str(line) + "." + str(column)) word = "" print(words) [...]
This code will produce the following result as we start typing:
Now you can see, every time we push a key it gives us the list of all words with it’s starting points combined in a format similar to dictionary.
So we have the words, we have the points now we have to use them.
Highlighting words
For this we will have to see if the word is “Hello” or “world” and add a tag that will highlight it. Now we add this to our “highlight” function:
[...] for i in words: i = i.split() #this splits an element to i = ["word", ":", "starting point"] if len(i) < 3: #we need this in case user types double white space which results in i = [":", "starting point"] i.insert(0, " ") if i[0] == "Hello": #i[0] stands for "word" self.txt.tag_config("hlight1", foreground="red") #we named this tag hlight1 self.txt.tag_add("hlight1", str(i[2].split(".")[0]) + "." + str(int(i[2].split(".")[1])-len(i[0])), i[2]) if i[0] == "world": self.txt.tag_config("hlight2", foreground="blue") #we named this tag hlight2 self.txt.tag_add("hlight2", str(i[2].split(".")[0]) + "." + str(int(i[2].split(".")[1])-len(i[0])), i[2]) [...]
And if we run it:
Looks like we don’t have any problems here, right! But we do.
Explaining our issue
If you experiment a bit more, you can see that in cases like this, the word “Hello” or any other word gets colored blue:
So how to fix this? To know how to fix it, we must first find out why did it happen!
It happens because two tags are overlapping, in our case hlight2 is overlapping hlight1. When the for loop runs the hlight1 tag is already there and hlight2 is over it, giving it the priority. And if we want our code to work, we must remove the tag hlight2 (or hlight1, it works vice versa to) every time it gets over a word that isn’t “world”. So what we will do is “refresh” the tags every time we run highlight function…
Fixing the issue
To achieve this, all we have to do is delete all of the tags and then let them be reassigned.
So to delete them we just add this before our ‘for’ loop in ‘highlight’ function:
[...] for tag in self.txt.tag_names(): self.txt.tag_delete(tag) for i in words: i = i.split()...... [...]
And that’s it! As simple as that! Here’s a look into our new working output:
I hope this article was helpful for you and keep coding!
Complete code
from tkinter import * class Files(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.pack(fill=BOTH, expand=1) self.bind_all("<Key>", self.highlight) self.txt = Text(self) self.txt.pack(fill=BOTH, expand=1) def highlight(self, event=0): file_text = self.txt.get("1.0", END+"-1c") + " " #a blank space at the end is for easier separating words words = [] #we will store words along with their starting point line = 1 #} column = -1 #}these are starting points that will help us in the following 'for' loop word = "" #} #now we have to find words and assign them their line and column for char in file_text: word += char column += 1 if char == "\n": #here a word stops words.append(word[:-1] + " : " + str(line) + "." + str(column)) word = "" line += 1 column = -1 if char == " ": #here a word stops words.append(word[:-1] + " : " + str(line) + "." + str(column)) word = "" print(words) for tag in self.txt.tag_names(): #deletes all tags so it can refresh them later self.txt.tag_delete(tag) for i in words: i = i.split() #this splits an element to i = ["word", ":", "starting point"] if len(i) < 3: #we need this in case user types double white space which results in i = [":", "starting point"] i.insert(0, " ") if i[0] == "Hello": #i[0] stands for "word" self.txt.tag_config("hlight1", foreground="red") #we named this tag hlight1 self.txt.tag_add("hlight1", str(i[2].split(".")[0]) + "." + str(int(i[2].split(".")[1])-len(i[0])), i[2]) if i[0] == "world": #i[0] stands for "word" self.txt.tag_config("hlight2", foreground="blue") #we named this tag hlight2 self.txt.tag_add("hlight2", str(i[2].split(".")[0]) + "." + str(int(i[2].split(".")[1])-len(i[0])), i[2]) root = Tk() top = Frame(root) top.pack(fill=BOTH, expand=0) bottom = Frame(root) bottom.pack() ex = Files(root) ex.pack(side="bottom") root.geometry("600x500-600-150") root.mainloop()