Reputation: 53
I have a scrollable frame with the mousewheel bound to scrolling, but when the frame is smaller than the canvas I am able to scroll above it - how can I keep the frame at the top of the canvas?
Here is a minimal version of the code:
import tkinter as tk
class Gui:
def __init__(self, master):
self.root = master
self.canvas = tk.Canvas(self.root)
self.frame = tk.Frame(self.canvas,bg='white')
self.scroll = tk.Scrollbar(self.canvas,orient='vertical', command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side='right', fill='y')
self.canvas.place(relheight=1, relwidth=0.85, relx=0.15)
self.canvas_frame = self.canvas.create_window((0,0), window=self.frame, anchor='nw')
self.frame.bind('<Configure>', self.onFrameConfigure)
self.canvas.bind_all('<MouseWheel>', lambda event: self.canvas.yview_scroll(int(-1*(event.delta/120)), 'units'))
self.addToFrame()
def onFrameConfigure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'))
def addToFrame(self):
self.label = tk.Label(self.frame,text='Label')
self.label.pack()
if __name__ == "__main__":
root = tk.Tk()
gui = Gui(root)
root.mainloop()
Upvotes: 4
Views: 1258
Reputation: 16169
You can define your own yview()
method that does the scrolling only when not the whole content of the canvas is visible. For that I used self.canvas.yview()
, which returns (0.0, 1.0)
if all the canvas content is visible. Then I used the custom yview()
method both as the scrollbar command and in the mouse wheel binding.
import tkinter as tk
class Gui:
def __init__(self, master):
self.root = master
self.canvas = tk.Canvas(self.root)
self.frame = tk.Frame(self.canvas,bg='white')
self.scroll = tk.Scrollbar(self.canvas,orient='vertical', command=self.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side='right', fill='y')
self.canvas.place(relheight=1, relwidth=0.85, relx=0.15)
self.canvas_frame = self.canvas.create_window((0,0), window=self.frame, anchor='nw')
self.frame.bind('<Configure>', self.onFrameConfigure)
self.canvas.bind_all('<MouseWheel>', lambda event: self.yview('scroll', int(-1*(event.delta/120)), 'units'))
self.addToFrame()
def onFrameConfigure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox('all'))
def addToFrame(self):
self.label = tk.Label(self.frame,text='Label')
self.label.pack()
def yview(self, *args):
if self.canvas.yview() == (0.0, 1.0):
return
self.canvas.yview(*args)
if __name__ == "__main__":
root = tk.Tk()
gui = Gui(root)
root.mainloop()
Upvotes: 7