Python – Tkinter Canvas & Scrollbar

canvaspythonscrollbartkinter

I have found several questions and answers related to this but none of the solutions make me understand why this code doesn't work:

root=tk.Tk()

vscrollbar = tk.Scrollbar(root)

c= tk.Canvas(root,background = "#D2D2D2",yscrollcommand=vscrollbar.set)

vscrollbar.config(command=c.yview)
vscrollbar.pack(side=tk.LEFT, fill=tk.Y) 

f=tk.Frame(c) #Create the frame which will hold the widgets

c.pack(side="left", fill="both", expand=True)
c.create_window(0,0,window=f)

testcontentA = tk.Label(f,wraplength=350 ,text=r"Det er en kendsgerning, at man bliver distraheret af læsbart indhold på en side, når man betragter dens websider, som stadig er på udviklingsstadiet. Der har været et utal af websider, som stadig er på udviklingsstadiet. Der har været et utal af variationer, som er opstået enten på grund af fejl og andre gange med vilje (som blandt andet et resultat af humor).")
testcontentB = tk.Button(f,text="anytext")
testcontentA.pack()
testcontentB.pack()

f.pack()

c.config(scrollregion=c.bbox("all"))

root.mainloop()

I have a tkinter window which has dynamically generated content – which means need to be able to scroll down if there are two many widgets to be displayed on screen. I hope to be able to populate the frame 'f' with the widgets and then use the canvas.create_window() function to display it in a scrollable way.

Right now the window is displayed but the scrollbar is not enabled – its like the scrollregion is not correct or the link between the scrollbar and the canvas is not correct.

Best Answer

If you are embedding a frame in a canvas you must use create_window, not pack. The first step is to remove f.pack().

Second, you need to set the bbox after tkinter has had a chance to display the widgets since their size cannot be computed until they are actually drawn on the screen.

A simple way to accomplish that is to call root.update() before calling c.config(scrollregion=c.bbox("all")), or schedule that command to be run with after_idle.

Another bug in your code (I'm assuming...) is that you create the window at (0,0) but don't set the anchor. That means that the internal frame will be centered at (0,0) when I'm guessing you want the upper left corner to be at (0,0).

Change your create_window call to look like this:

c.create_window(0,0,window=f, anchor='nw')