I have a label into which I am going to put content of different sizes. I would like to know how high I need to make the label so that I can size the window so it can stay the same for the different content sizes. I have a strategy, but it seems more complicated then it should be.
I want to set a label to a given width and wraplength:
l = Label(root)
l['width'] = 30
l['wraplength'] = 244
l['text'] = "testing this"
Now I want to query the label to find how many lines are used. l[‘height’] stays at 0, so the best I have been able to come up with is to use l.winfo_height() and convert the height given in pixels to the number of lines used. Nothing in dir(l) seems to give me the information directly, but this strategy is fragile to font changes and other changes.
Any suggestions?
Update: using Brian Oakley’s suggestion (which is similar to what I got on usenet) I have the following approximation to a solution (needs polishing, e.g. doesn’t take into account that Label breaks at whitespace):
import Tkinter as Tk
import tkFont
import random
import sys
def genstr (j):
rno = random.randint(4,50)
ret_val = str(j) + ":"
for i in range (0, rno):
ret_val += "hello" + str(i)
return ret_val
def gendata (lh):
ret_val = []
for i in range(0,lh):
ret_val.append (genstr (i))
return ret_val
data = gendata (100)
root = Tk.Tk()
font = tkFont.Font(family='times', size=13)
class lines:
def __init__ (self):
self.lastct = 1 # remember where the cutoff was last work from there
def count (self, text, cutoff = 400):
global font
no_lines = 1
start_idx = 0
idx = self.lastct
while True:
if idx > len (text):
idx = len (text)
# shrink from guessed value
while font.measure (text[start_idx:idx - 1]) > cutoff:
if idx <= start_idx:
print "error"
sys.exit ()
else:
idx -= 1
self.lastct = idx - start_idx # adjust since was too big
# increase from guessed value (note: if first shrunk then done)
while (idx < len (text)
and font.measure (text[start_idx:idx]) < cutoff):
idx += 1
self.lastct = idx - start_idx # adjust since was too small
# next line has been determined
print "*" + text[start_idx:idx-1] + "*"
if idx == len(text) and font.measure (text[start_idx:]) < cutoff:
return no_lines
elif idx == len(text):
return no_lines + 1
else:
no_lines += 1
start_idx = idx - 1
idx = start_idx + self.lastct
lin = lines()
for i in range(0,len(data)):
lin.count(data[i], 450)
for i in range(0,min(len(data),10)):
l = Tk.Label(root)
l.pack()
l['text'] = data[i]
print i
no = lin.count (data[i], 450)
print "computed lines", no
l['width'] = 50
l['justify'] = Tk.LEFT
l['anchor'] = 'w'
l['wraplength'] = 450
l['padx']=10
l['pady'] = 5
l['height'] = no
l['font'] = font
if i % 2 == 0:
l['background'] = 'grey80'
else:
l['background'] = 'grey70'
root.mainloop()
You are correct that the
heightattribute doesn’t change. That attribute doesn’t tell you the actual height, only the height it is configured to be. The actual height depends on factors such as how much text is in it, the wrap length, the font, and how the widget geometry is managed.tkinter Font objects have a
measuremethod which lets you determine how tall and wide a string is for a given font. You can get the font for the widget and use that method to determine how much space is required for your string.