tkinter and widget placement after resizing
John Posner
jjposner at snet.net
Thu May 7 23:56:48 EDT 2009
jamieson wrote:
> i.e. start out with a window like this:
>
> [1][4][7]
> [2][5][8]
> [3][6][9]
>
>
> make the main window larger and end up with this:
>
> [1][6]
> [2][7]
> [3][8]
> [4][9]
> [5
Here's a solution, using Label widgets for clarity. The keys are:
* start numbering from zero, not one
* use divmod() on an item's index within the list to determine the
item's column/row position
* bind the <Configure> event for window resizing
# redo_layout.py
import sys
from Tkinter import *
CHAR_WIDTH = 10
PAD = 3
INIT_COL_COUNT = 3
def grid_positions(count, numcols):
"""
return a generator for (colnum, rownum) position tuples,
given the total number of items and the number of columns
the first column is filled with items, then the second, etc.
"""
numrows, rem = divmod(count, numcols)
# need an extra row if there was a remainder
if rem:
numrows += 1
# return value is a generator
return ( divmod(i, numrows) for i in range(count) )
def place_labels(event):
"""
reposition all the items in the sequence "label_list"
"""
# assumption: all labels have same width
label_width = label_list[0].winfo_width()
window_width = frm.winfo_width()
# calculate new column count
new_col_count = window_width // (label_width+PAD)
# get new position iterator
pos_iter = grid_positions(LABEL_COUNT, new_col_count)
# redo layout
for lab in label_list:
lab.grid_forget()
colnum, rownum = pos_iter.next()
lab.grid(column=colnum, row=rownum, padx=PAD, pady=PAD)
def create_labels(count):
"""
create a list of Label items,
with text "1", "2", etc.
"""
return [ Label(frm, bg='cyan', width=CHAR_WIDTH, text="%d" % i)
for i in range(count) ]
if __name__ == "__main__":
try:
LABEL_COUNT = int(sys.argv[1])
except (ValueError, IndexError):
print "ERROR: Must specify number of labels"
sys.exit(1)
# Tkinter window and whole-window Frame
root = Tk()
frm = Frame(root)
frm.pack(expand=True, fill=BOTH)
# create some labels
label_list = create_labels(LABEL_COUNT)
# perform initial layout
pos_iter = grid_positions(LABEL_COUNT, INIT_COL_COUNT)
for lab in label_list:
coloff, rowoff = pos_iter.next()
lab.grid(column=coloff, row=rowoff, padx=PAD, pady=PAD)
del pos_iter
# event configuration: redo the layout when the window size changes
frm.bind('<Configure>', place_labels)
# go
root.mainloop()
More information about the Python-list
mailing list