I am trying to learn more about Python and Tkinter and so I’ve tried to implement a scrolling frame – but the scrollbar isn’t working at all. I’ve looked at several tutorials and stackoverflow threads and, so far as I can tell, I’m doing it right. I’m obviously not, though, so can anyone help, please? Here’s my code
import tkinter as tk
import tkinter.ttk as ttk
import platform
class ScrollFrame(ttk.Frame): # {{{
def __init__(self, parent, height='5c'): # {{{
super().__init__(parent)
self.canvas = tk.Canvas(self, height=height)
self.viewport = tk.Frame(self.canvas)
self.vsb = tk.Scrollbar(self, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side='right', fill='y')
self.canvas.pack(expand=True, fill='both')
self.canvas_window = self.canvas.create_window(
0,
0,
window=self.viewport,
anchor="nw",
)
self.viewport.bind('<Configure>', self._on_configure)
self.canvas.bind('<Configure>', self._on_configure)
self.viewport.bind("<Enter>", self._on_enter)
self.viewport.bind("<Leave>", self._on_leave)
# }}}
def _on_configure(self, event): # {{{
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
self.canvas.itemconfig(self.canvas_window, height=event.height)
self.canvas.itemconfig(self.canvas_window, width=event.width)
# }}}
def _on_mouse_wheel(self, event): # {{{
if platform.system() == "Windows":
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
elif platform.system() == "Darwin":
self.canvas.yview_scroll(int(-1 * event.delta), "units")
else:
if event.num == 4:
self.canvas.yview_scroll(-1, "units")
elif event.num == 5:
self.canvas.yview_scroll(1, "units")
# }}}
def _on_enter(self, event): # {{{
if platform.system() == "Linux":
self.canvas.bind_all("<Button-4>", self._on_mouse_wheel)
self.canvas.bind_all("<Button-5>", self._on_mouse_wheel)
else:
self.canvas.bind_all("<MouseWheel>", self._on_mouse_wheel)
# }}}
def _on_leave(self, event): # {{{
if platform.system() == "Linux":
self.canvas.unbind_all("<Button-4>")
self.canvas.unbind_all("<Button-5>")
else:
self.canvas.unbind_all("<MouseWheel>")
# }}}
# }}}
labels = {}
count = 1
def add_label():
global labels
global count
labels[count] = ttk.Label(sf.viewport, text=f'Label #{count}')
labels[count].pack()
count += 1
root = tk.Tk()
sf = ScrollFrame(root)
ttk.Button(root, text='Add', command=add_label).pack()
sf.pack()
root.mainloop()
I realise my mistake is probably going to be fairly trivial, but I just can’t see it.
1