gefdel
gefdel

Reputation: 59

Scrollable frame does not fill canvas

I use Python 2.7 and I have a scrollable frame where the canvas is not shrinking to fit the frame I want to make scrollable.

I looked at this question for an answer but it does not work when I run it: How to resize a scrollable frame to fill the canvas?

When I print the width of the frame inside the canvas, it says 0.

I also ran the code from the answer of this question on my computer : Scrollable Frame does not resize properly using tkinter in Python but it will still show the white canvas to the left of the labels, and it does not resize when the labels are deleted.

It looks like this:

Canvas not resizing to fit scrollable frame

This is my code, based on the answer in this question: Adding a scrollbar to a group of widgets in Tkinter

from Tkinter import *

class Scrollable_frame(Frame):

    def __init__(self, parent, title, values):

        self.parent = parent

        Frame.__init__(self, self.parent)

        self.canvas = Canvas(self, borderwidth=0, background="#ffffff")
        self.scrollbar = Scrollbar(self, command=self.canvas.yview)
        self.innerFrame = Radiobutton_frame(self.canvas,title,values)

        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.grid(row=0, column=0, sticky= N+S)
        self.scrollbar.grid(row=0, column=1, sticky = N+S)
        self.canvas.create_window((0,0),window = self.innerFrame,anchor="nw")

        self.innerFrame.bind("<Configure>", self.set_canvas_scrollregion)

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


    def set_canvas_scrollregion(self, event):

        width = event.width - 4
        self.canvas.itemconfigure("self.innerFrame ", width=width)
        self.canvas.config(scrollregion=self.canvas.bbox("all"))


class Radiobutton_frame(LabelFrame):

    def __init__(self, parent, title, values):

        """            
        In: parent - Canvas
            title - String
            values - List of Int
        """

        self.radiobuttons = {}
        self.parent = parent

        self.selection = StringVar()
        self.selection.set("init")

        LabelFrame.__init__(self, self.parent, text = title)

        for value in values:
            self.add_radiobutton(value)


    def add_radiobutton(self, value):

        """
        Adds a radiobutton to the frame.

        In: item - String
        """

        # Associate to same variable to make them function as a group
        self.radiobuttons[value] = Radiobutton(master = self,
                                                variable = self.selection,
                                                text = value,
                                                value = value)
        self.radiobuttons[value].pack(anchor=W)

# Usage example

root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
scrollableFrame = Scrollable_frame(root, "Canvas not resizing", range(30))
scrollableFrame.grid(row=0, column=0, sticky=N+S+E+W)

if __name__ == '__main__':
    root.mainloop()

Upvotes: 1

Views: 1765

Answers (1)

Nae
Nae

Reputation: 15345

I don't think above question's code snippet fits to a Minimal, Complete, and Verifiable example but at the very least it's runnable.


You have three mistakes compared to that of: How to resize a scrollable frame to fill the canvas?

The most significant of which is that in the linked question, the OP uses the option tags where you don't. Replace:

self.canvas.create_window((0,0),window = self.innerFrame,anchor="nw")

with:

self.canvas.create_window((0,0),window = self.innerFrame, anchor="nw", tags="my_tag")

Another mistake is that you're binding the event of a frame's resizing as opposed to the actual Canvas' resizing, also pointed out in Bryan's comment here. Replace:

self.innerFrame.bind("<Configure>", self.set_canvas_scrollregion)

with:

self.canvas.bind("<Configure>", self.set_canvas_scrollregion)

Lastly, tkinter doesn't seem to accept space character with tags, replace:

self.canvas.itemconfigure("self.innerFrame ", width=width)

with:

self.canvas.itemconfigure("my_tag", width=width)

Finally, you should have:

from Tkinter import *

class Scrollable_frame(Frame):

    def __init__(self, parent, title, values):

        self.parent = parent

        Frame.__init__(self, self.parent)

        self.canvas = Canvas(self, borderwidth=0, background="#ffffff")
        self.scrollbar = Scrollbar(self, command=self.canvas.yview)
        self.innerFrame = Radiobutton_frame(self.canvas,title,values)

        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.grid(row=0, column=0, sticky= N+S)
        self.scrollbar.grid(row=0, column=1, sticky = N+S)
        self.canvas.create_window((0,0),window = self.innerFrame,anchor="nw",
                                                                tags="my_tag")

        self.canvas.bind("<Configure>", self.set_canvas_scrollregion)

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


    def set_canvas_scrollregion(self, event):

        width = event.width - 4
        self.canvas.itemconfigure("my_tag", width=width)
        self.canvas.config(scrollregion=self.canvas.bbox("all"))


class Radiobutton_frame(LabelFrame):

    def __init__(self, parent, title, values):

        """            
        In: parent - Canvas
            title - String
            values - List of Int
        """

        self.radiobuttons = {}
        self.parent = parent

        self.selection = StringVar()
        self.selection.set("init")

        LabelFrame.__init__(self, self.parent, text = title)

        for value in values:
            self.add_radiobutton(value)


    def add_radiobutton(self, value):

        """
        Adds a radiobutton to the frame.

        In: item - String
        """

        # Associate to same variable to make them function as a group
        self.radiobuttons[value] = Radiobutton(master = self,
                                                variable = self.selection,
                                                text = value,
                                                value = value)
        self.radiobuttons[value].pack(anchor=W)

# Usage example

root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
scrollableFrame = Scrollable_frame(root, "Canvas not resizing", range(30))
scrollableFrame.grid(row=0, column=0, sticky=N+S+E+W)

if __name__ == '__main__':
    root.mainloop()

Upvotes: 2

Related Questions