In this tutorial, I will explain how to create Python Tkinter text editor. As a Python developer working on various projects, I recently faced the challenge of building a custom text editor for my team. Through this process, I discovered the uses and flexibility of Tkinter for creating graphical user interfaces (GUIs). In this article, I’ll share my experience and guide you through the steps to build your own Python Tkinter text editor.
Create Python Tkinter Text Editor
Let us how to create a Python TKinter text editor step by step.
Read How to Create Animations in Python with Tkinter?
1. Set Up the Tkinter Environment
To get started with Tkinter, you don’t need to install any additional packages. Tkinter comes bundled with Python, so you can start using it right away. Simply import the Tkinter module in your Python script:
import tkinter as tkBy convention, we import Tkinter tk to keep our code concise and readable.
2. Create the Main Window
The first step in building our text editor is to create the main window. This window will serve as the foundation for our application. Here’s how you can create the main window:
window = tk.Tk()
window.title("Python Tkinter Text Editor")
window.geometry("800x600")In this code snippet, we create an instance of the Tk class, which represents the main window. We set the title of the window using the title() method and specify its dimensions using the geometry() method. Feel free to adjust the window size according to your preference.
Check out How to Master Python Tkinter Events?
3. Add a Text Widget
The heart of our text editor is the text widget. Tkinter provides the Text widget, which allows users to enter and edit multi-line text. Let’s add a text widget to our main window:
text_area = tk.Text(window, font=("Arial", 12))
text_area.pack(expand=True, fill='both')Here, we create an instance of the Text widget and pass the main window (window) as its parent. We also specify the font family and size using the font parameter. The pack() method is used to position the text widget within the window. By setting expand=True and fill='both', the text widget will expand to fill the available space.
Read How to Create Tabbed Interfaces in Python with Tkinter Notebook Widget?
4. Implement Basic Functionality
Now that we have our main window and text widget set up, let’s add some basic functionality to our text editor.
File Menu
An essential feature of any text editor is the ability to open, save, and create new files. We can add a file menu to our editor using Tkinter’s Menu widget. Here’s an example:
menu_bar = tk.Menu(window)
file_menu = tk.Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New", command=new_file)
file_menu.add_command(label="Open", command=open_file)
file_menu.add_command(label="Save", command=save_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=window.quit)
menu_bar.add_cascade(label="File", menu=file_menu)
window.config(menu=menu_bar)In this code, we create a menu bar (menu_bar) and a file menu (file_menu). We add commands to the file menu using the add_command() method, specifying the label and the corresponding function to be executed when the menu item is clicked. The add_separator() method adds a separator line between menu items. Finally, we add the file menu to the menu bar using the add_cascade() method and configure the window to use the menu bar.
Check out How to Create an On/Off Toggle Switch in Python Tkinter?
Implement File Operations
To make the file menu functional, we need to implement the corresponding file operations. Here are examples of how you can implement the new_file(), open_file(), and save_file() functions:
def new_file():
text_area.delete(1.0, tk.END)
def open_file():
file_path = filedialog.askopenfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")])
if file_path:
text_area.delete(1.0, tk.END)
with open(file_path, "r") as file:
text_area.insert(tk.END, file.read())
def save_file():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")])
if file_path:
with open(file_path, "w") as file:
file.write(text_area.get(1.0, tk.END))The new_file() function clears the content of the text widget using the delete() method. The open_file() function opens a file dialog using filedialog.askopenfilename() , allows the user to select a file, and inserts the content of the selected file into the text widget. The save_file() function opens a file dialog using filedialog.asksaveasfilename() , allows the user to choose a location and file name, and saves the content of the text widget to the specified file.
5. Advanced Features
To enhance the functionality of our text editor, we can add more advanced features. Let’s explore a few examples.
Read How to Validate User Input in Python Tkinter?
Syntax Highlighting
Syntax highlighting improves the readability of code by applying different colors to different parts of the code based on the programming language. We can achieve syntax highlighting in our text editor using the pygments library. Here’s an example of how to implement syntax highlighting for Python code:
from pygments import lex
from pygments.lexers import PythonLexer
def highlight_syntax(event=None):
content = text_area.get(1.0, tk.END)
text_area.mark_set("range_start", 1.0)
data = text_area.get("range_start", tk.END)
for token, content in lex(data, PythonLexer()):
text_area.mark_set("range_end", "range_start + {}c".format(len(content)))
text_area.tag_add(str(token), "range_start", "range_end")
text_area.mark_set("range_start", "range_end")In this code, we import the lex function and PythonLexer class from the pygments library. The highlight_syntax() function retrieves the content of the text widget, uses the PythonLexer to tokenize the code, and applies corresponding tags to each token using the tag_add() method. We can bind this function to a key event or call it whenever the content of the text widget changes.
Check out How to Create a Search Box with Autocomplete in Python Tkinter?
Line Numbers
Adding line numbers to our text editor can greatly improve the user experience, especially when working with larger files. Here’s how you can add line numbers to the text widget:
line_numbers = tk.Text(window, width=4, padx=5, takefocus=0, border=0, background='lightgray', state='disabled')
line_numbers.pack(side='left', fill='y')
def update_line_numbers(event=None):
line_numbers.config(state='normal')
line_numbers.delete(1.0, tk.END)
lines = text_area.get(1.0, tk.END).split('\n')
for i, line in enumerate(lines):
line_numbers.insert(tk.END, f"{i+1}\n")
line_numbers.config(state='disabled')In this code, we create a separate text widget (line_numbers) to display the line numbers. We set its width, padding, and background color accordingly. The update_line_numbers() function retrieves the content of the main text widget, splits it into lines, and inserts the corresponding line numbers into the line_numbers widget. We can bind this function to the <Key> and <Button-1> events of the main text widget to update the line numbers whenever the content changes or the user clicks on the text area.
Read How to Create Message Boxes with Python Tkinter?
Put It All Together
Now that we have explored various features and functionalities, let’s put everything together to create our complete Python Tkinter text editor:
import tkinter as tk
from tkinter import filedialog
from pygments import lex
from pygments.lexers import PythonLexer
def new_file():
text_area.delete(1.0, tk.END)
def open_file():
file_path = filedialog.askopenfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")])
if file_path:
text_area.delete(1.0, tk.END)
with open(file_path, "r") as file:
text_area.insert(tk.END, file.read())
def save_file():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")])
if file_path:
with open(file_path, "w") as file:
file.write(text_area.get(1.0, tk.END))
def highlight_syntax(event=None):
content = text_area.get(1.0, tk.END)
text_area.mark_set("range_start", 1.0)
data = text_area.get("range_start", tk.END)
for token, content in lex(data, PythonLexer()):
text_area.mark_set("range_end", "range_start + {}c".format(len(content)))
text_area.tag_add(str(token), "range_start", "range_end")
text_area.mark_set("range_start", "range_end")
def update_line_numbers(event=None):
line_numbers.config(state='normal')
line_numbers.delete(1.0, tk.END)
lines = text_area.get(1.0, tk.END).split('\n')
for i, line in enumerate(lines):
line_numbers.insert(tk.END, f"{i+1}\n")
line_numbers.config(state='disabled')
window = tk.Tk()
window.title("Python Tkinter Text Editor")
window.geometry("800x600")
menu_bar = tk.Menu(window)
file_menu = tk.Menu(menu_bar, tearoff=0)
file_menu.add_command(label="New", command=new_file)
file_menu.add_command(label="Open", command=open_file)
file_menu.add_command(label="Save", command=save_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=window.quit)
menu_bar.add_cascade(label="File", menu=file_menu)
window.config(menu=menu_bar)
line_numbers = tk.Text(window, width=4, padx=5, takefocus=0, border=0, background='lightgray', state='disabled')
line_numbers.pack(side='left', fill='y')
text_area = tk.Text(window, font=("Arial", 12))
text_area.pack(expand=True, fill='both')
text_area.bind('<Key>', highlight_syntax)
text_area.bind('<Button-1>', update_line_numbers)
window.mainloop()This code combines all the features we discussed earlier, including the file menu, syntax highlighting, and line numbers. The highlight_syntax() function is bound to the <Key> event of the text widget, so it gets
Let us see how the output looks in the screenshot below.

Check out How to Save Text to a File Using Python Tkinter?
Image Editor
An image editor is used to edit images by rotating, adding borders, adding contrast, increasing brightness, adding borders, and making the image blur. With the help of image editing, we can improve image visibility.
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from tkinter.filedialog import askopenfilename,asksaveasfilename
from PIL import Image, ImageTk, ImageFilter, ImageEnhance, ImageOps
import os
# contrast border thumbnail
ws = Tk()
ws.title("Simple Photo Editor")
ws.geometry("640x640")
# create functions
def selected():
global image_path, image
image_path = filedialog.askopenfilename(initialdir=os.getcwd())
image = Image.open(image_path)
image.thumbnail((350, 350))
#imgg = img.filter(ImageFilter.BoxBlur(0))
image1 = ImageTk.PhotoImage(image)
canvas2.create_image(300, 210, image=image1)
canvas2.image=image1
def blur(event):
global image_path, image1, imgg
for m in range(0, v1.get()+1):
image = Image.open(image_path)
image.thumbnail((350, 350))
imgg = image.filter(ImageFilter.BoxBlur(m))
image1 = ImageTk.PhotoImage(imgg)
canvas2.create_image(300, 210, image=image1)
canvas2.image=image1
def brightness(event):
global image_path, image2, image3
for m in range(0, v2.get()+1):
image = Image.open(image_path)
image.thumbnail((350, 350))
imgg = ImageEnhance.Brightness(image)
image2 = imgg.enhance(m)
image3 = ImageTk.PhotoImage(image2)
canvas2.create_image(300, 210, image=image3)
canvas2.image=image3
def contrast(event):
global image_path, image4, image5
for m in range(0, v3.get()+1):
image = Image.open(image_path)
image.thumbnail((350, 350))
imgg = ImageEnhance.Contrast(image)
image4 = imgg.enhance(m)
image5 = ImageTk.PhotoImage(image4)
canvas2.create_image(300, 210, image=image5)
canvas2.image=image5
def rotate_image(event):
global image_path, image6, image7
image = Image.open(image_path)
image.thumbnail((350, 350))
image6 = image.rotate(int(Rotate_combo.get()))
image7 = ImageTk.PhotoImage(image6)
canvas2.create_image(300, 210, image=image7)
canvas2.image=image7
def flip_image(event):
global image_path, image8, image9
image = Image.open(image_path)
image.thumbnail((350, 350))
if Flip_combo.get() == "FLIP LEFT TO RIGHT":
image8 = image.transpose(Image.FLIP_LEFT_RIGHT)
elif Flip_combo.get() == "FLIP TOP TO BOTTOM":
image8 = image.transpose(Image.FLIP_TOP_BOTTOM)
image9 = ImageTk.PhotoImage(image8)
canvas2.create_image(300, 210, image=image9)
canvas2.image=image9
def image_border(event):
global image_path, image10, image11
image = Image.open(image_path)
image.thumbnail((350, 350))
image10 = ImageOps.expand(image, border=int(Border_combo.get()), fill=95)
image11 = ImageTk.PhotoImage(image10)
canvas2.create_image(300, 210, image=image11)
canvas2.image=image11
image1 = None
image3 = None
image5 = None
image7 = None
image9 = None
image11 = None
def save():
global image_path, imgg, image1, image2, image3, image4, image5, image6, image7, image8, image9, image10, image11
#file=None
ext = image_path.split(".")[-1]
file=asksaveasfilename(defaultextension =f".{ext}",filetypes=[("All Files","*.*"),("PNG file","*.png"),("jpg file","*.jpg")])
if file:
if canvas2.image==image1:
imgg.save(file)
elif canvas2.image==image3:
image2.save(file)
elif canvas2.image==image5:
image4.save(file)
elif canvas2.image==image7:
image6.save(file)
elif canvas2.image==image9:
image8.save(file)
elif canvas2.image==image11:
image10.save(file)
# create labels, scales and comboboxes
blurr = Label(ws, text="Blur:", font=("ariel 17 bold"), width=9, anchor='e')
blurr.place(x=15, y=8)
v1 = IntVar()
scale = ttk.Scale(ws, from_=0, to=10, variable=v1, orient=HORIZONTAL, command=blur)
scale.place(x=150, y=10)
bright = Label(ws, text="Brightness:", font=("ariel 17 bold"))
bright.place(x=8, y=50)
v2 = IntVar()
Scale1 = ttk.Scale(ws, from_=0, to=10, variable=v2, orient=HORIZONTAL, command=brightness)
Scale1.place(x=150, y=55)
contrast = Label(ws, text="Contrast:", font=("ariel 17 bold"))
contrast.place(x=35, y=92)
v3 = IntVar()
Scale2 = ttk.Scale(ws, from_=0, to=10, variable=v3, orient=HORIZONTAL, command=contrast)
Scale2.place(x=150, y=100)
Rotate = Label(ws, text="Rotate:", font=("ariel 17 bold"))
Rotate.place(x=370, y=8)
values = [0, 90, 180, 270, 360]
Rotate_combo = ttk.Combobox(ws, values=values, font=('ariel 10 bold'))
Rotate_combo.place(x=460, y=15)
Rotate_combo.bind("<<ComboboxSelected>>", rotate_image)
Flip = Label(ws, text="Flip:", font=("ariel 17 bold"))
Flip.place(x=400, y=50)
values1 = ["FLIP LEFT TO RIGHT", "FLIP TOP TO BOTTOM"]
Flip_combo = ttk.Combobox(ws, values=values1, font=('ariel 10 bold'))
Flip_combo.place(x=460, y=57)
Flip_combo.bind("<<ComboboxSelected>>", flip_image)
border = Label(ws, text="Add border:", font=("ariel 17 bold"))
border.place(x=320, y=92)
values2 = [i for i in range(10, 45, 5)]
Border_combo = ttk.Combobox(ws, values=values2, font=("ariel 10 bold"))
Border_combo.place(x=460, y=99)
Border_combo.bind("<<ComboboxSelected>>", image_border)
# create canvas to display image
canvas2 = Canvas(ws, width="600", height="420", relief=RIDGE, bd=2)
canvas2.place(x=15, y=150)
# create buttons
button1 = Button(ws, text="Select Image", bg='black', fg='gold', font=('ariel 15 bold'), relief=GROOVE, command=selected)
button1.place(x=100, y=595)
button2 = Button(ws, text="Save", width=12, bg='black', fg='gold', font=('ariel 15 bold'), relief=GROOVE, command=save)
button2.place(x=280, y=595)
button3 = Button(ws, text="Exit", width=12, bg='black', fg='gold', font=('ariel 15 bold'), relief=GROOVE, command=ws.destroy)
button3.place(x=460, y=595)
ws.mainloop()Let us see how the output looks in the screenshot below.

We came up with an output where we can select an image from a local location and edit it inside a box.
Check out How to Cancel Scheduled Functions with after_cancel() in Python Tkinter?
Conclusion
In this tutorial, I explained how to create Python Tkinter text editor. I discussed step by step the whole process of creating a text editor and by putting it all together we run the code. I have also given an example to the image editor.
You may like to read:
- How to Create GUI Layouts with Python Tkinter Separator?
- How to Add Functions to Python Tkinter?
- How to Create a Filter() Function in Python Tkinter?

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.