Tkinter refresh/update scrollbar to fit canvas content

Viewed 393

After loading a new frame in a canvas the scrollbar does not fit the content.
If I manually resize the window the scrollbar fits the content.
How could force the scrollbar to fit the content, when loading the frame?
Here is code that reproduces my problem:

from tkinter import *

class MyApp:
    def __init__(self):
        self.root = Tk()
        self.mainframe = Frame(self.root)
        self.mainframe.pack(fill=BOTH, expand=True)
        self.mainframe.columnconfigure(0, weight=1)

        self.contentCanvas = Canvas(self.mainframe)
        self.contentCanvas.grid(sticky=N + S + W + E)

        self.horizontalBar = Scrollbar(self.mainframe, orient=HORIZONTAL)
        self.horizontalBar.grid(rowspan=2, sticky=W + E + S)
        self.horizontalBar.config(command=self.contentCanvas.xview)
        self.contentCanvas.config(xscrollcommand=self.horizontalBar.set)

        self.contentFrame = Frame(self.contentCanvas)
        self.content = Frame(self.contentFrame)
        self.content.grid()
        Button(self.content, text="Load Long Content", command=self.loadLongContent).grid()

        self.contentCanvas.bind("<Configure>", lambda e: self.contentCanvas.configure(scrollregion=self.contentFrame.bbox("all")))
        self.contentCanvas.create_window((0, 0), window=self.contentFrame, anchor="nw")


    def run(self):
        self.root.mainloop()

    def loadContentFrame(self, frame):
        self.content.grid_forget()
        self.content.destroy()
        self.content = frame
        self.content.grid()

    def loadLongContent(self):
        longFrame = Frame(self.contentFrame)
        for i in range(100):
            Label(longFrame, text=i*i).grid(row=0, column=i)
        self.loadContentFrame(longFrame)

if __name__ == "__main__":
    app = MyApp()
    app.run()

Pictures:
Before loading new content:

After loading new content:

After resizing the window a bit:

1 Answers

I came up with a solution that somewhat works(based on Helder Sepulvedas idea).
I added this in the in init:
self.expand = False
This was added in loadFrame:

        width = self.root.winfo_width()
        height = self.root.winfo_height()
        if self.expand:
            self.root.geometry('{width}x{height}'.format(width=width + 1, height=height + 1))
            self.expand = False
        else:
            self.root.geometry('{width}x{height}'.format(width=width - 1, height=height - 1))
            self.expand = True

A solution where the size of the window does not change would still be nice.
Also I recommend to set the position of root in init.

Related