tkinter and widget placement after resizing

J

jamieson

Hello,

I've got a fairly simple GUI that places pmw.EntryFields into a window
starting in the upper left corner. When the first column is filled
with these widgets I'd like to start a new column and continue
placement, and so on. It is working now with the grid manager if I
explicitly set the max number of widgets per column, but if I resize
the main window there is wasted space as the number of widgets per
column is fixed. I'd like to find a design that could change the
number of widgets per column when the window is resized. Any
suggestions?

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]
 
J

John Posner

jamieson said:
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()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top