Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter string in a font measures differently than same in Text widget as string grows

The Text object holding a string (in a specified font) seems to give inconsistent results depending on the length of the string. For example:

from Tkinter import *
import tkFont
root=Tk()
t_Font = tkFont.Font(family='Helvetica', size=12, weight='bold')
t_text='New.'
t_frame = Frame(root, bd=0, height=10, width=t_Font.measure(t_text))
t = Text(master=t_frame, height=1, width=len(t_text), bd=1, font=t_Font, padx=0)
print '\n\nMeasured:', t_Font.measure(t_text), 'Frame req:', \
      t_frame.winfo_reqwidth(), 'As Text:', t.winfo_reqwidth()

Measured: 38 Frame req: 38 As Text: 38

t_text='New title.'
t_frame = Frame(root, bd=0, height=10, width=t_Font.measure(t_text))
t = Text(master=t_frame, height=1, width=len(t_text), bd=1, font=t_Font, padx=0)
print '\n\nMeasured:', t_Font.measure(t_text), 'Frame req:', \
      t_frame.winfo_reqwidth(), 'As Text:', t.winfo_reqwidth()

Measured: 69 Frame req: 69 As Text: 92

The additional 6 characters increased the measured size and frame size by 31 pixels, but the Text object has increased by 54.

What causes this?

like image 385
Mike Murnane Avatar asked Oct 28 '25 12:10

Mike Murnane


1 Answers

I realize its been 7 months, but wanted to answer this for anyone that ends up here like I did.

TL;DR: If you were using a fixed-width font, then it would have been a match (e.g. "Courier New"). But Helvetica is a proportional font, so its characters are not all the same width.

The tkFont.measure() and Frame.winfo_reqwidth() are both using the actual size for those strings of text in that font/weight/size, because their widths are specified in pixels.

The Text widget on the other hand has its width specified in characters.

So it's taking the number of characters each time and trying to guess for that font/weight/size how big to make the widget to handle them - but not the exact characters you're using. It uses the zero character, "0", as its average character size.

If you change your second set of t_text, t_frame, and t to t_text2, t_frame2, and t2, then pack() everything and start root.mainloop(), you can play around with the 2 widgets created. The first one with "New." typed in doesn't even show the "." because the created field is slightly too small, while the second widget shows "New title." with extra spaces left. Now if you delete those and enter "0000" for the first widget, and "0000000000" for the second, you'll see the widgets filled up exactly.

I found this through reading the Tcl/Tk docs for text -width on the text manual page for Tk Built-In Commands.

like image 61
Bob Willan Avatar answered Oct 31 '25 03:10

Bob Willan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!