Tom Fuller Tom Fuller - 2 months ago 20
Python Question

Fitting text into a rectangle (width x by height y) with tkinter

I'm trying to make a program which will fit text into a rectangle (x by y) depending on the text, the font and the font size

Here is the code

def fit_text(screen, width, height, text, font):
measure_frame = Frame(screen) # frame
measure_frame.pack()
measure_frame.pack_forget()
measure = Label(measure_frame, font = font) # make a blank label
measure.grid(row = 0, column = 0) # put it in the frame

##########################################################
# make a certain number of lines
##########################################################

words = text.split(" ")
lines = []
num = 0
previous = 0
while num <= len(words):
measure.config(text = " ".join(words[previous:num])) # change text
line_width = measure.winfo_width() # get the width
print(line_width)
if line_width >= width: # if the line is now too long
lines.append(" ".join(words[previous:num - 1])) # add the last vsion which wasn't too long
previous = num - 1 # previous is now different
num = num + 1 # next word
lines.append(" ".join(words[previous:])) # add the rest of it
return "\n".join(lines)

from tkinter import *
window = Tk()
screen = Canvas(window)
screen.pack()
text = fit_text(screen, 200, 80, "i want to fit this text into a rectangle which is 200 pixels by 80 pixels", ("Purisa", 12))
screen.create_rectangle(100, 100, 300, 180)
screen.create_text(105, 105, text = text, font = ("Purisa", 12), anchor = "nw")


The problem with this is no matter what text is in the label the result from
measure.winfo_width()
is always 1. Here is where I found this from but it doesn't seem to work for me

Answer

The problem with your code is that you're using the width of a widget, but the width will be 1 until the widget is actually laid out on the screen and made visible, since the actual width depends on a number of factors that aren't present until that happens.

You don't need to put the text in a widget in order to measure it. You can pass a string to font.measure() and it will return the amount of space required to render that string in the given font.

For python 3.x you can import the Font class like this:

from tkinter.font import Font

For python 2.x you import it from the tkFont module:

from tkFont import Font

You can then create an instance of Font so that you can get information about that font:

font = Font(family="Purisa", size=18)
length = font.measure("Helli, world")
print "result:", length

You can also get the height of a line in a given font with the font.metrics() method, giving it the argument "linespace":

height = font.metrics("linespace")
Comments