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
47
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.