2

I'm having a really hard time trying to achieve a decdent GUI layout in tkinter. I'm aiming for the layout on the left, but didn't get any further than the layout on the right:

enter image description here enter image description here

I feel completely lost in all that different layout managers. This is my code so far:

from Tkinter import *

class ScrolledCanvas:
    def __init__(self, master, width=500, height=350):
        Label(master, text="top of master frame").pack(side=TOP)
        self.control=Frame(master)
        self.control.pack(side=BOTTOM, fill=X, padx=2)
        Label(self.control, text="bottom of master frame").pack()
        self.grid = Frame(master, bd=2, bg="red")
        self.canvas = Canvas(master, relief=SUNKEN, borderwidth=2, 
                             scrollregion=('-11c', '-11c', '50c', '20c')) 
        self.vscroll = Scrollbar(master, command=self.canvas.yview) 
        self.canvas.configure(yscrollcommand=self.vscroll.set) 

        self.grid.pack(expand=YES, fill=BOTH, padx=1, pady=1)
        self.grid.rowconfigure(0, weight=1, minsize=0)
        self.grid.columnconfigure(0, weight=1, minsize=0)

        self.canvas.grid(padx=1, in_=self.grid, pady=1, row=0,
                         column=0, rowspan=1, columnspan=1, sticky='news')
        self.vscroll.grid(padx=1, in_=self.grid, pady=1, row=0,
                          column=1, rowspan=1, columnspan=1, sticky='news')
        self.oldFill = None
        self.canvas = self.fillCanvas(self.canvas)

    def fillCanvas(self, theCanvas):
        for i in range(10):
            frame = Frame(theCanvas)
            Label(frame, text="text for inner frame (%s)" % i).pack(side=TOP)
            Button(frame, text="button %s.1" % i).pack(side=LEFT)
            Button(frame, text="button %s.2" % i).pack(side=LEFT)
            frame.pack()
        return theCanvas

if __name__ == '__main__':
    root = Tk()
    scroll = ScrolledCanvas(root)
    root.mainloop()

For some reason the scrollregion expands to full size, making all scrollbar actions obsolete (This code bases on a scrollbar example where the canvas is filled with some rectangles, and everything scrolls really nice). I probably missed something fundamental about resizing, because most components seem to completely ignore their fixed width and height.

I'm looking for help on how to get this example to work with tkinter. I know that there are other layout technologies, and I know that other modules offer scrollable widgets out of the box. But unless completely unavoidable I really like to stick to this example, which cost me at least 3 nights so far...

nbro
  • 15,395
  • 32
  • 113
  • 196
Jan Groth
  • 14,039
  • 5
  • 40
  • 55
  • 1
    I know this is a bit old, but you may want to look at this: http://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-grid-of-widgets-in-tkinter – samwyse Aug 26 '12 at 04:46

1 Answers1

4

You cannot pack (or grid, or place) widgets into the canvas and expect them to scroll. Instead, you must use the create_window method.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks, this was truly an eye opener!!! While this lets the canvas scroll the way I want, it leaves me with the new problem that I have to position the frames manually on the canvas, or did I get this wrong? In my application amount and size of frames will vary - so I was hoping that I can create each frame and leave it to some sort of layout manager to put them nicely on top of each other... Is there a chance that I can achieve this? (I'm not stuck with the canvas widget, I'm just looking for any working combinations of widgets in order to get the desired layout...) – Jan Groth Sep 16 '11 at 11:40
  • Yes, you have to position them manually. Typically what I do is create a frame for all the content, and pack (or grid, or place) the content in that frame. Then I just have to add that one frame to the canvas. It becomes very manageable that way. Another trick is to bind to the `` event of the canvas -- it will get triggered whenever the canvas is resized. You can then use information from that event to resize that one frame to exactly fit the width of the canvas. – Bryan Oakley Sep 16 '11 at 15:30
  • Thanks again, I will do it the way you proposed. – Jan Groth Sep 16 '11 at 15:48