Insert vertical line below tabs in tkinter.text

Question:

I am creating a code editor as my project, and I think it is nice to have vertical lines under tabs so its easier for the coder. I want to draw a vertical line below tabs (I think the image below will be better to understand what I want, Just a screenshot from vs code):

enter image description here

Here you can see that there is a vertical line under def and I think these are pretty useful for me so that I won’t make any indentation errors while I am coding. Now I want exactly a feature like this in my code editor. To simplify things I will upload a sample code below.

from tkinter import *

root = Tk()


txt = Text(root) # What changes do I have to make to this text widget so the lines appear like it does in the image
txt.pack()

root.mainloop()
Asked By: ss3387

||

Answers:

The text widget doesn’t directly support this. You can fake it by using ascii line drawing characters, but it would probably be a lot of work. It should be doable, though.

You can do this if you base your IDE on a canvas rather than a Text widget, but the text-editing ability of the canvas text item would be very cumbersome compared to the text widget.

All of that being said, with a little creativity you can get something close to what you want with tags. The idea is to add a tag to the character that you want to appear as a line. If you set the tag to have a different color than the text, it will look like a vertical line. The problem, however, is that you don’t have much control over the width of the line. You might have some luck using the bgstipple option, which allows you to apply a bitmap to the region.

Here’s an example to illustrate the idea.

import tkinter as tk
import tempfile

def add_markup(text, start=None, end="end"):
    text.mark_set("current", start or "1.0")
    text.tag_remove("markup", "current", end)
    while text.compare("current", "<", end):
        if text.get("current") == " ":
            text.tag_add("markup", "current", "current+1c")
            text.mark_set("current", "current+4c")
        else:
            text.mark_set("current", f"current +1l linestart")

root = tk.Tk()

text = tk.Text(root)
text.tag_configure("markup", background='#f0f0f0', bgstipple='@line.xbm', fgstipple='@line.xbm')
text.pack(fill="both", expand=True)

text.bind(
    "<Any-KeyRelease>",
    lambda event: add_markup(event.widget, "insert linestart", "insert lineend")
)

def load_this_file(text):
    with open(__file__, "r") as f:
        text.insert("1.0", f.read())

load_this_file(text)
add_markup(text)

root.mainloop()

This is what it looks like on my machine:

screenshot

Answered By: Bryan Oakley