Title: Make a scrolled frame that responds to the mouse wheel in tkinter and Python
This example extends the one in the post Make a scrolled frame in tkinter and Python so you can use the mouse's scroll wheel to scroll the frame vertically. There are two pieces to this: binding mouse wheel events and performing the scrolling.
Binding Mouse Wheel Events
You may recall from the earlier post that the ScrolledFrame class provides a configure_frame method that you should call after you add widgets to the ScrolledFrame. The new example adds some code to that method to bind the MouseWheel event for the controls inside the frame. The following code shows the configure_frame method with the new code highlighted in blue.
def configure_frame(self):
self.frame.update_idletasks()
width = self.frame.winfo_reqwidth()
height = self.frame.winfo_reqheight()
self.canvas.config(scrollregion=(0, 0, width, height))
# Bind the mouse wheel to scroll the canvas.
for child in widget_and_descendants(self.canvas):
child.bind('<MouseWheel>', self.wheel_scroll)
The new code calls the following widget_and_descendants function to get a list of a widget and its descendants.
def widget_and_descendants(parent):
'''Return this widget and all of its descendants.'''
results = [parent]
for child in parent.winfo_children():
results += widget_and_descendants(child)
return results
This method creates a list holding the parent widget. It then uses the parent's winfo_children method to loop through that widget's children. It recursively calls each child's widget_and_descendants method and adds the returned widgets to results to the results list.
After it finishes added all of the parent widget's descendants to the results list, the function returns it.
(Note: On X11 systems you may need to bind the <Button-4> and <Button-5> events instead of <MouseWheel>.)
Scrolling
When any of the widgets receives a MouseWheel event, the ScrolledFrame executes the following code.
def wheel_scroll(self, event):
''' Scroll the canvas.'''
units = -int(event.delta / 30)
self.canvas.yview_scroll(units, 'units')
The event.delta parameter tells you how far the wheel has rotated. The sign of that value tells which direction the wheel turned.
In Windows, at least, a negative value means the top of the wheel has been rotated down. Normally that means you want to move the scrolling area up so you can see what's farther down. To do that, the code negates the value and passes it to the canvas widget's yview_scroll method. (Conversely for positive values.)
Some sources online recommend dividing event.delta by 120 in Windows and possibly other values in other operating systems to make the result scroll be a reasonable amount. You can do that if you want to adjust the scrolling speed, but I found dividing by 30 gives a result similar to the scrolling I get when I scroll the wheel over the vertical scrollbar so that's what this example uses.
Conclusion
I changed the main program to add more widgets to the scrolling area so I could test the scrolling, but the code given here shows the only changes needed to the ScrolledFrame class.
Download the example to see additional details.
|