'tkinter tab width incorrect

When creating text on a canvas using the create_text method the width of a tab is not what it should be, as indicated by font.measure.

import tkinter as tk
from tkinter.font import Font

root = tk.Tk()

canvas = tk.Canvas(root, width=300, height=300)
canvas.pack()

font = Font(family='Arial', size=12)

s1 = "a\tb"
s2 = "a    c"
print("Width:", s1, font.measure(s1))  # Width: a        b 30
print("Width:", s2, font.measure(s2))  # Width: a    c 33

canvas.create_text(10, 10, text=s1, font=font, anchor="nw")
canvas.create_text(10, 50, text=s2, font=font, anchor="nw")

root.mainloop()

The results of font.measure suggest that the line with spaces should be a little longer, but what it displays is:

Width of tab is larger than width of spaces

Showing that the width of the tab is significantly larger than the spaces. Using different fonts will result in differently sized tabs, but still inaccurate measurements. The measured width of the text without tabs is correct.

How can I get the correct tab width? Is this a bug?



Solution 1:[1]

The problem you've highlighted is due to the Canvas text object not having a tabs attribute.

Maybe someone knows how to work around that but usually when displaying tabulation a tk.Text object is used which has font and tabs attributes.

So the easiest solution is to make a tk.Text object T, define font and tabs, insert your messages into T then insert T into a Canvas window W.

Something like this.

import tkinter as tk
from tkinter import font

app = tk.Tk()

fixed = 1 # test Arial & Courier New
FONT = font.Font(family = ["arial", "courier new"][fixed], size = 12)
wide = 4 * FONT.measure(0)
high = FONT.metrics("linespace")
dent = (wide, tk.LEFT)

canvas = tk.Canvas(app)
canvas.grid(sticky =tk.NSEW)

s1, s2 = "a\tb\n", "a   c"

T = tk.Text(
    canvas,
    background = "SystemButtonFace",
    relief = tk.FLAT,
    font = FONT,
    tabs = dent,
    width = 20,
    height = 3,
    highlightthickness = 0,
    borderwidth = 0)

W = canvas.create_window(wide, high, window = T, anchor = tk.NW)

T.insert("1.0", s1)
T.insert("insert", s2)

app.mainloop()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Derek