Text Widget size

Jeff Epler jepler at unpythonic.net
Tue May 21 12:44:00 EDT 2002


I have not succeeded in solving this problem.  The following function
comes close.  However, Tk doesn't easily yield up the information
necessary.

The principle is to use the 'dlineinfo' command to get information about
each line in the text widget in turn, and then from that find out the
height and width of the entire window.

The required width is the maximum x coordinate returned by dlineinfo(),
and the required height is the sum of the required height for each line.
These numbers are in pixel units.

Then, since units for height= and width= of a text are in character
units, it is necessary to compute the number of pixels in the same way
that Tk computes it---from the width of the character 0, and the overall
height of the font.  These are accessible via "font measure" and "font
metrics" commands, but don't seem to be directly available via the Tkinter
wrapper.

The 'update_idletasks' call is necessary to let the widget configure
itself.  The height is set to 2 so that 'dlineinfo' returns the true
height of the line, and this may still be wrong if any single line is
taller than 2 default lines (probably easily true with embedded windows)
(put a number like 100 here instead?).  This may cause the window to
"twitch" since it is resized twice during this process.

Good luck -- it's not a pretty corner of Tk that you find yourself in...

Jeff

#-----------------------------------------------------------------------
import Tkinter, math

def fittext(t):
    t.configure(width=1, height=2, wrap="none")
    t.update_idletasks()
    end = int(float(t.index("end")))
    x = y = 0
    for line in range(0, end):
        idx = "%d.0" % line
        t.see(idx)
        bb = t.dlineinfo(idx)
        print bb, bb[3] - bb[1] + 1, bb[2] - bb[0] + 1
        y = y + bb[3]
        x = max(x, bb[2])
    font = t.cget("font")
    print t
    h = int(t.tk.call("font", "measure", font, "0"))
    v = int(t.tk.call("font", "metrics", font, "-linespace"))
    print x, y, h, v
    t.configure(width=int(math.ceil(x/h))+1, height=int(math.ceil(y/v)))
    t.see("0.0")

# demo
t = Tkinter.Text()
t.insert("end", open("fittext.py").read())
t.tag_add("blah", 0.0, "end")
t.tag_configure("blah", font="helvetica -24")
t.pack()
fittext(t)
t.mainloop()





More information about the Python-list mailing list