# -*- coding: utf-8 -*-
"""Add support for the mousewheel to scrolled widgets
Based on a version:
# Version: 0.22
# Author: Miguel Martinez Lopez
# Uncomment the next line to see my email
# print("Author's email: ",
# "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
with minor changes.
"""
import platform
OS = platform.system()
[docs]class MousewheelSupport(object):
# implementation of singleton pattern
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
def __init__(
self,
root,
horizontal_factor=2,
vertical_factor=2,
natural_scroll_direction=True,
):
"""Initialize the instance"""
self._active_area = None
self.natural_scroll_direction = natural_scroll_direction
if isinstance(horizontal_factor, int):
self.horizontal_factor = horizontal_factor
else:
raise Exception("Vertical factor must be an integer.")
if isinstance(vertical_factor, int):
self.vertical_factor = vertical_factor
else:
raise Exception("Horizontal factor must be an integer.")
if OS == "Linux":
root.bind_all("<4>", self._on_mousewheel, add="+")
root.bind_all("<5>", self._on_mousewheel, add="+")
else:
# Windows and MacOS
root.bind_all("<MouseWheel>", self._on_mousewheel, add="+")
def _on_mousewheel(self, event):
if self._active_area:
self._active_area.onMouseWheel(event)
def _mousewheel_bind(self, widget):
self._active_area = widget
def _mousewheel_unbind(self):
self._active_area = None
[docs] def add_support_to(
self,
widget=None,
xscrollbar=None,
yscrollbar=None,
what="units",
horizontal_factor=None,
vertical_factor=None,
):
if xscrollbar is None and yscrollbar is None:
return
if xscrollbar is not None:
horizontal_factor = horizontal_factor or self.horizontal_factor
xscrollbar.onMouseWheel = self._make_mouse_wheel_handler(
widget, "x", horizontal_factor, what, self.natural_scroll_direction
)
xscrollbar.bind(
"<Enter>",
lambda event, scrollbar=xscrollbar: self._mousewheel_bind(scrollbar),
)
xscrollbar.bind("<Leave>", lambda event: self._mousewheel_unbind())
if yscrollbar is not None:
vertical_factor = vertical_factor or self.vertical_factor
yscrollbar.onMouseWheel = self._make_mouse_wheel_handler(
widget, "y", vertical_factor, what, self.natural_scroll_direction
)
yscrollbar.bind(
"<Enter>",
lambda event, scrollbar=yscrollbar: self._mousewheel_bind(scrollbar),
)
yscrollbar.bind("<Leave>", lambda event: self._mousewheel_unbind())
main_scrollbar = yscrollbar if yscrollbar is not None else xscrollbar
if widget is not None:
if isinstance(widget, list) or isinstance(widget, tuple):
list_of_widgets = widget
for widget in list_of_widgets:
widget.bind("<Enter>", lambda event: self._mousewheel_bind(widget))
widget.bind("<Leave>", lambda event: self._mousewheel_unbind())
widget.onMouseWheel = main_scrollbar.onMouseWheel
else:
widget.bind("<Enter>", lambda event: self._mousewheel_bind(widget))
widget.bind("<Leave>", lambda event: self._mousewheel_unbind())
widget.onMouseWheel = main_scrollbar.onMouseWheel
@staticmethod
def _make_mouse_wheel_handler(
widget, orient, factor=1, what="units", natural_scroll_direction=True
):
view_command = getattr(widget, orient + "view")
if natural_scroll_direction:
if OS == "Linux":
def onMouseWheel(event):
if event.num == 4:
view_command("scroll", factor, what)
elif event.num == 5:
view_command("scroll", (-1) * factor, what)
elif OS == "Windows":
def onMouseWheel(event):
view_command("scroll", int((event.delta / 120) * factor), what)
elif OS == "Darwin":
def onMouseWheel(event):
view_command("scroll", (-1) * event.delta, what)
else:
if OS == "Linux":
def onMouseWheel(event):
if event.num == 4:
view_command("scroll", (-1) * factor, what)
elif event.num == 5:
view_command("scroll", factor, what)
elif OS == "Windows":
def onMouseWheel(event):
view_command(
"scroll", (-1) * int((event.delta / 120) * factor), what
)
elif OS == "Darwin":
def onMouseWheel(event):
view_command("scroll", event.delta, what)
return onMouseWheel