0

I need this simple form to: 1) correctly expand the fields when the window size is adjusted and 2) correctly scroll the list of fields.

I've tried every way I can think of and only 1 of the 2 above conditions are ever true. This code expands properly but does not scroll. Without frame2, and adding the fields to frame or canvas the opposite is true.

class test(Tkinter.Tk):

    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def makeform(self, root, fields):
        i = 0
        for field in fields:
            Label(root, text=field + ": ", anchor=W).grid(row=i)
            entry = Entry(root)
            entry.grid(row=i, column=1, sticky=E+W)
            entries[field] = entry
            i += 1

    def initialize(self):

        frame = Frame(self)
        frame.rowconfigure(0, weight=1)
        frame.columnconfigure(0, weight=1)
        frame.grid(sticky=N+S+E+W)

        canvas = Canvas(frame, width=900, height=800, bg='pink')
        canvas.grid(row=0, column=0, sticky=N+S+E+W)
        canvas.columnconfigure(0,weight=1)
        canvas.rowconfigure(0,weight=1)

        frame2 = Frame(canvas)
        frame2.grid(row=0, column=0, sticky=N+S+E+W)
        frame2.columnconfigure(1, weight=1)

        vscrollbar = Scrollbar(frame2,orient=VERTICAL)
        vscrollbar.grid(row=0, column=2, sticky=N+S)

        vscrollbar.config(command=canvas.yview)

        canvas.configure(yscrollcommand=vscrollbar.set)

        self.grid_rowconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        names = {'a','long','list','of','names','here'}
        self.makeform(frame2, names)

        Button(self, text='Quit', command=self.quit).grid(row=1, column=0, sticky=W, pady=4)

        canvas.create_window(0, 0)
        canvas.config(scrollregion=canvas.bbox(ALL))

        self.grid()

if __name__ == "__main__":

    entries = {}

    app = test(None)
    app.title('Hi ')
    app.mainloop()

Update

Integrating Bryan's example below, this works for scrolling but does not expand the fields when the window is resized. I tried adding weight=1 to the second column of the frame but it does not help. How do I prevent the frame from shrinking?

class test(Tkinter.Frame):

    def __init__(self,parent):
        Tkinter.Frame.__init__(self, root)
        self.canvas = Tkinter.Canvas(root, borderwidth=0, background="#ffffff")
        self.frame = Tkinter.Frame(self.canvas, background="#ffffff")
        self.vsb = Tkinter.Scrollbar(root, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((0,0), window=self.frame, anchor="nw",
                                  tags="self.frame")

        self.frame.bind("<Configure>", self.onFrameConfigure)

        self.populate()

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def makeform(self, fields):
        i = 0
        for field in fields:
            Label(self.frame, text=field + ": ", anchor=W).grid(row=i)
            entry = Entry(self.frame)
            entry.grid(row=i, column=1, sticky=E+W)
            entries[field] = entry
            i += 1
        Button(self.frame, text='Quit', command=self.quit).grid(row=i, column=0, sticky=W, pady=4)


    def populate(self):
        names = {'a','long','list','of','names','here'}
        self.makeform(names)
        self.frame.columnconfigure(1, weight=1)
        self.frame.grid_columnconfigure(1, weight=1)

if __name__ == "__main__":

    entries = {}

    root=Tk()
    test(root).pack(side="top", fill="both", expand=True)
    root.mainloop()
manicmethod
  • 886
  • 1
  • 8
  • 13

1 Answers1

2

There are at least three problems in your code.

First, the frame to be scrolled must be a part of the canvas. You can't use pack or grid to place it in the canvas, you must use create_window. You're calling create_window but you aren't telling it what window to add.

Second, the scrollbars are children of the frame, but I'm assuming those are the scrollbars you want to scroll the canvas. The need to be outside of the inner frame, and outside of the canvas.

Third, you need to set up a binding to the canvas's <Configure> event so that you can resize the inner frame and recompute the scrollregion of the canvas.

A complete working example of a scrollable frame is in this answer: https://stackoverflow.com/a/3092341/7432

Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685