3

My goal here is to have the right edge of the text box fit to the end of the text. This happens automatically when using TkFixedFont, but when using TkDefaultFont (which is what I would like to use), there is trailing whitespace added to the end. This is what it looks like with no trailing space, with TkFixedFont:

Notice that the trailing space is minimal. I would like this same near-none amount of trailing space, but when using TkDefaultFont.


The following is a minimal example of my code:

from tkinter import *
root = Tk()

myText = 'sample text'

text = Text(root, bg='#c2d9ff', 
            font='TkDefaultFont',
            height=1, width=len(myText)
        )
text.insert(INSERT, myText)
text.place(x=0,y=0)
root.mainloop()

I have searched for around two hours now for everything related to spacing, trailing space, types of widgets (e.g., label vs text, etc.), widget options, etc., and have found nothing unfortunately.

It appears to somehow be proportional to the length of the text, which I cannot figure out. Using the code above, when myText = 'Some text goes here', the trailing spacing is:

But when I put a longer text string, the trailing space seems to proportionally increase:

Any suggestions on how to cut out the trailing space would be much appreciated!

camball
  • 43
  • 6
  • can't you use a `Label`? as for why this happens it is probably because you are not using a monospaced font (for example "Courier New" or seemingly the "TkFixedFont"), that would mean that it calculates the average width of the characters and uses that for calculating the space, so if you were to use only the characters that had were the widest it would fit as it should – Matiiss Oct 20 '21 at 18:47
  • @Matiiss I had originally used a `Label`, but switched to using a `Text` because I need to use tags to change the color of a subset of the characters in the text. Still doesn't make sense to me, unfortunately. – camball Oct 20 '21 at 20:01

2 Answers2

1

What you're seeing isn't whitespace characters, it's just empty space. The actual width is the given number of characters times the number of pixels in an average-sized character (I think tkinter uses the character "0"). In a variable-width font, "." is narrower than, say "W", so the actual width of a string depends on what characters are in the string.

In other words, if your text is made up of narrow characters (eg: "...........") there will be more empty space, if it's made up of wide characters (eg: "WWWWWWWWWWW") there will be less.

What you can do is compute the actual width of the text using the measure method of a font object. Once you know exactly how many pixels your text string requires, you can use that information to set the size of your text widget appropriately.

from tkinter import *
from tkinter.font import nametofont

root = Tk()

myText = 'sample text'
font = nametofont("TkDefaultFont")
width = font.measure(myText)

text = Text(root, bg='#c2d9ff',
            font='TkDefaultFont',
            height=1, width=len(myText)
        )
text.insert(INSERT, myText)
text.place(x=0,y=0, width=width)
root.mainloop()

Note that when you use the width with place, that specifies the entire width of the widget, not just the width inside the border. You'll need to adjust the width to account for the text widget border and highlight thickness, and maybe a few other pixels for the interior padding.

For example, if the text itself takes up 100 pixels and you have a two pixel border and a one pixel highlight ring for the text widget, you'll need to add at least six pixels to the width when used in the call to place.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • I do realise it is empty space, just can't figure it out. I used your method, but it doesn't quite calculate the spacing correctly. It truncates the last few letters off of the text. I'll mess around with the font pixel sizes though and see if I can get somewhere with that. – camball Oct 20 '21 at 21:17
  • The `measure` method should be pretty accurate, within just a few pixels. Though, if you have formatting applied that may affect the required width. You'll probably want to adjust the width a little since the `width` in `place` is the total width including the borders. If your text widget has a border you'll have to adjust the width. – Bryan Oakley Oct 20 '21 at 21:22
1

You can get the area occupied by myText using Text.dlineinfo() and adjust the width of text based on the result and other settings related to space occupied horizontally, e.g. border width, padx, etc:

myText = 'sample text'*4

text = Text(root, bg='#c2d9ff',
            font='TkDefaultFont',
            height=1
        )
text.insert(INSERT, myText)
text.place(x=0, y=0)

text.update_idletasks() # make sure the widget is laid out completely
x, y, w, h, _ = text.dlineinfo(INSERT)
text.place(width=x+w+(text['bd']+text['padx'])*2) # adjust the width
acw1668
  • 40,144
  • 5
  • 22
  • 34