Salim
That shouldn't be too difficult: just create your text with the minimum
width and height (1 and 1...) and bind a callback to the <KeyRelease> event
getting the number of lines in the text and the length of the longest line
and set them respectively as the height and width of the Text object:
t = Text(..., width=1, height=1)
def resize(event):
lines = t.get(1.0, END).splitlines()
maxW = 0
if lines: maxW = max([len(l) for l in lines])
t.configure(width=maxW, height=len(lines))
t.bind("<KeyRelease>", resize)
Be warned: this doesn't work in all cases... If you do an t.insert or a
t.delete, you'll have to call the resize function manually. There are also
far more complex issues with non-default fonts, especially proportional
fonts, and tab management, that will make the simple method above miserably
fail... But you get the idea.
HTH
--
- Eric Brunel <eric....@pragmadev.com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com
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()
Here is the method (called resize()) in class TextMap that does
what you asked for when called without parameters. class TextMap
is of type Tkinter.Frame and has a .text attribute of type
Tkinter.Text. Works with python 1.5.2 or later.
I think you can figure out how it is implemented now, for more
details: the class TextMap is in the textui module I submitted to
parnassus, you can also get it at
http://www.cwi.nl/~jacob/textui.py
def resize(self, height=None, width=None):
if not (height or width): # fit window to displayed
# text inside
textstr = self.gettext()
self.width = 0
self.height = 0
for s in string.split(textstr, '\n'):
self.height = self.height + 1
if len(s) > self.width: self.width = len(s)
self.resize(height=self.height, width=self.width)
else:
if height:
self.height = height
self.text.config(height=height)
if width:
self.width = width
self.text.config(width=width)
self.text.update()
def gettext(self):
"Return the data (string) in the window"
return self.text.get('1.0', END+'-1c') # first
# through last END points to just beyond the last
# character in the text string '-1c' because this
# widget adds a trailing newline char to its
# contents