Details

A pure Tkinter scrollable frame that actually works!

This is a vertically scrolled frame; making a horizontally scrolled frame or one that is scrollable in both directions is left as an exercise for the reader.

Code

   1 class VerticalScrolledFrame(Frame):
   2     """A pure Tkinter scrollable frame that actually works!
   3 
   4     * Use the 'interior' attribute to place widgets inside the scrollable frame
   5     * Construct and pack/place/grid normally
   6     * This frame only allows vertical scrolling
   7     
   8     """
   9     def __init__(self, parent, *args, **kw):
  10         Frame.__init__(self, parent, *args, **kw)            
  11 
  12         # create a canvas object and a vertical scrollbar for scrolling it
  13         vscrollbar = Scrollbar(self, orient=VERTICAL)
  14         vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
  15         canvas = Canvas(self, bd=0, highlightthickness=0,
  16                         yscrollcommand=vscrollbar.set)
  17         canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
  18         vscrollbar.config(command=canvas.yview)
  19 
  20         # reset the view
  21         canvas.xview_moveto(0)
  22         canvas.yview_moveto(0)
  23 
  24         # create a frame inside the canvas which will be scrolled with it
  25         self.interior = interior = Frame(canvas)
  26         interior_id = canvas.create_window(0, 0, window=interior,
  27                                            anchor=NW)
  28 
  29         # track changes to the canvas and frame width and sync them,
  30         # also updating the scrollbar
  31         def _configure_interior(event):
  32             # update the scrollbars to match the size of the inner frame
  33             size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
  34             canvas.config(scrollregion="0 0 %s %s" % size)
  35             if interior.winfo_reqwidth() != canvas.winfo_width():
  36                 # update the canvas's width to fit the inner frame
  37                 canvas.config(width=interior.winfo_reqwidth())
  38         interior.bind('<Configure>', _configure_interior)
  39 
  40         def _configure_canvas(event):
  41             if interior.winfo_reqwidth() != canvas.winfo_width():
  42                 # update the inner frame's width to fill the canvas
  43                 canvas.itemconfigure(interior_id, width=canvas.winfo_width())
  44         canvas.bind('<Configure>', _configure_canvas)
  45 
  46         return

Notes

This is NOT based on http://wiki.tcl.tk/1152 because it's much too complicated Tcl for me.

The drawback to this implementation is that you have to manually use the .interior attribute all of the time (except when packing/placing/griding the scrolled frame itself), but all things considered I think that's a reasonable price to pay for a simple, clean, working implementation such as this. This drawback could probably be worked around with Tcl hacks, but IMHO it's not worth it.

tkinter: VerticalScrolledFrame (last edited 2010-07-26 11:59:13 by localhost)