Question

I know there is a lot of similar questions here, but none of these that i found seems to work for me.Here is the deal: I need to load dynamically checkboxes inside a frame, but i dont know how many can they be.So I need a scrollbar.I've read that there is no way to put a scrollbar into frame, unless i put the frame into canvas and add the scrollbar to the canvas.I think the problem is something about scrollregion,but I'm not very sure.

Here is that part of my code :

def checkboxes_container(self):
    # Checkboxes frame
    self.checkboxes_frame = \
        tk.Frame(self,
                 height=450,
                 bg='red', bd=0,
                 highlightthickness=0)
    # Canvas widget to add scroll to the checkboxes holder
    self.canvas = \
        tk.Canvas(self.checkboxes_frame,
                  bg='blue', bd=0,
                  highlightthickness=0)
    # Canvas sizer
    canvas_sizer = tk.Frame(self.canvas, height=350,
                            bg='#444444', bd=0,
                            highlightthickness=0)
    canvas_sizer.pack(side=tk.LEFT)
    # Checkboxes holder
    self.checkbox_pane = \
        tk.Frame(self.canvas,
                 bg='#444444', bd=0,
                 highlightthickness=0)
    self.checkbox_pane.grid_propagate(False)
    # Scrollbar for checkbox pane
    self.scrollbar = tk.Scrollbar(self.checkboxes_frame,
                                  bg='grey', bd=0,
                                  activebackground='#A3A3A3',
                                  troughcolor='#444444',
                                  width=16,
                                  orient=tk.VERTICAL)

    self.canvas.create_window(0, 0, window=self.checkbox_pane)
    # Grid holder
    self.checkboxes_frame.grid(row=1, column=0, sticky=tk.W+tk.E)
    # Grid widgets to the holder
    self.canvas.pack(expand=True, side=tk.LEFT, fill=tk.BOTH)
    self.checkbox_pane.pack(expand=True, fill=tk.BOTH)
    self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    self.scrollbar.config(command=self.canvas.yview)
    self.canvas.config(yscrollcommand=self.scrollbar.set,
                       scrollregion=
                       self.canvas.bbox('all'))

self is my basic frame widget where i put containers with other widgets(like this one)

I'll be very glad if someone help me.I'm trying to do this for all day...I must be very close...or very stupid

Thanks in advance Best regards

EDIT: Adding the edited code:

class ScrollableFrame(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, kwargs)

        # create a canvas object and a vertical scrollbar for scrolling it
        self.vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
        self.vscrollbar.pack(side='right', fill="y",  expand="false")
        self.canvas = tk.Canvas(self,
                                bg='#444444', bd=0,
                                height=350,
                                highlightthickness=0,
                                yscrollcommand=self.vscrollbar.set)
        self.canvas.pack(side="left", fill="both", expand="true")
        self.vscrollbar.config(command=self.canvas.yview)

        # reset the view
        self.canvas.xview_moveto(0)
        self.canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = tk.Frame(self.canvas, kwargs)
        self.canvas.create_window(0, 0, window=self.interior, anchor="nw")


class Application(tk.Frame):
    # ...

    def checkboxes_container(self):
        self.checkbox_pane = ScrollableFrame(self,
                                             bg='#444444')
        self.checkbox_pane.grid(row=1, column=0,
                                columnspan=3,
                                sticky='nwes')
Was it helpful?

Solution

It might be easier to create a class and then call it instead of Tkinter.Frame.

Note that there is an instance variable called interior that you need to use to display widgets inside the scrolling frame.

import Tkinter as tk

class ScrollableFrame(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)

        # create a canvas object and a vertical scrollbar for scrolling it
        self.vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
        self.vscrollbar.pack(side='right', fill="y",  expand="false")
        self.canvas = tk.Canvas(self,
                                bg='#444444', bd=0,
                                height=350,
                                highlightthickness=0,
                                yscrollcommand=self.vscrollbar.set)
        self.canvas.pack(side="left", fill="both", expand="true")
        self.vscrollbar.config(command=self.canvas.yview)

        # reset the view
        self.canvas.xview_moveto(0)
        self.canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = tk.Frame(self.canvas, **kwargs)
        self.canvas.create_window(0, 0, window=self.interior, anchor="nw")

        self.bind('<Configure>', self.set_scrollregion)


    def set_scrollregion(self, event=None):
        """ Set the scroll region on the canvas"""
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))


if __name__ == '__main__':
    root = tk.Tk()
    checkbox_pane = ScrollableFrame(root, bg='#444444')
    checkbox_pane.pack(expand="true", fill="both")

    def button_callback():
        for x in range(1,20):
            tk.Checkbutton(checkbox_pane.interior, text="hello world! %s" % x).grid(row=x, column=0)

    btn_checkbox = tk.Button(checkbox_pane.interior, text="Click Me!", command=button_callback)
    btn_checkbox.grid(row=0, column=0)
    root.mainloop()

Code taken from here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top