tkinter and widget placement after resizing

John Posner jjposner at snet.net
Fri May 8 05:56:48 CEST 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