# Version: 0.11
# Author: Miguel Martinez Lopez
# Uncomment the next line to see my email
# print("Author's email: ", "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
try:
from Tkinter import Canvas, Frame
from ttk import Scrollbar
from Tkconstants import *
except ImportError:
from tkinter import Canvas, Frame
from tkinter.ttk import Scrollbar
from tkinter.constants import *
import platform
OS = platform.system()
def build_mouse_wheel_handler(widget, orient, factor = 1, what="units"):
view_command = getattr(widget, orient+'view')
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
class Mousewheel_Support(object):
# implemetnation of singleton pattern
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Mousewheel_Support, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, root, horizontal_factor = 2, vertical_factor=2):
self._active_area = None
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_mouse_wheel, add='+')
root.bind_all('<5>', self._on_mouse_wheel, add='+')
else:
# Windows and MacOS
root.bind_all("<MouseWheel>", self._on_mouse_wheel, add='+')
def _on_mouse_wheel(self,event):
if self._active_area:
self._active_area.onMouseWheel(event)
def _on_mouse_enter_scrolling_area(self, widget):
self._active_area = widget
def _on_mouse_leave_scrolling_area(self):
self._active_area = None
def add_support_to(self, widget, xscrollbar=None, yscrollbar=None, what="units", horizontal_factor=None, vertical_factor=None):
if xscrollbar is not None and not hasattr(xscrollbar, 'onMouseWheel'):
horizontal_factor = horizontal_factor or self.horizontal_factor
xscrollbar.onMouseWheel = build_mouse_wheel_handler(widget,'x', self.horizontal_factor, what)
xscrollbar.bind('<Enter>', lambda event, scrollbar=xscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
xscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
if yscrollbar is not None and not hasattr(yscrollbar, 'onMouseWheel'):
vertical_factor = vertical_factor or self.vertical_factor
yscrollbar.onMouseWheel = build_mouse_wheel_handler(widget,'y', self.vertical_factor, what)
yscrollbar.bind('<Enter>', lambda event, scrollbar=yscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
yscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
main_scrollbar = yscrollbar if yscrollbar is not None else xscrollbar
if main_scrollbar is not None:
widget.bind('<Enter>',lambda event: self._on_mouse_enter_scrolling_area(widget))
widget.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
widget.onMouseWheel = main_scrollbar.onMouseWheel
class Scrolling_Area(Frame):
def __init__(self, master, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, outer_background=None, inner_frame=Frame, **kw):
Frame.__init__(self, master)
if outer_background:
self.configure(background=outer_background)
self._canvas = Canvas(self, highlightthickness=0)
self._canvas.grid(row=0, column=0, sticky="nsew")
if scroll_vertically:
self.yscrollbar = Scrollbar(self, orient=VERTICAL)
self.yscrollbar.grid(row=0, column=1,sticky=N+S)
self._canvas.configure(yscrollcommand=self.yscrollbar.set)
self.yscrollbar['command']=self._canvas.yview
else:
self.yscrollbar = None
if scroll_horizontally:
self.xscrollbar = Scrollbar(self, orient=HORIZONTAL)
self.xscrollbar.grid(row=1, column=0, sticky=E+W)
self._canvas.configure(xscrollcommand=self.xscrollbar.set)
self.xscrollbar['command']=self._canvas.xview
else:
self.xscrollbar = None
self.rowconfigure( 0, weight=1)
self.columnconfigure(0, weight=1)
self.innerFrame= inner_frame(self._canvas, **kw)
self.innerFrame.pack()
self._canvas.create_window(0, 0, window=self.innerFrame, anchor='nw', tags="inner_frame")
self._canvas.bind('<Configure>', self._on_configure_canvas)
Mousewheel_Support(self).add_support_to(self._canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar)
def _on_configure_canvas(self, event):
width = max(self.innerFrame.winfo_reqwidth(), event.width)
height = max(self.innerFrame.winfo_reqheight(), event.height)
self._canvas.configure(scrollregion="0 0 %s %s" % (width, height))
self._canvas.itemconfigure("inner_frame", width=width, height=height)
if __name__== '__main__':
try:
from Tkinter import Tk, Label
except ImportError:
from tkinter import Tk, Label
root = Tk()
scrolling_area = Scrolling_Area(root)
scrolling_area.pack(expand=1, fill=BOTH)
for i in range(20):
rowFrame = Frame(scrolling_area.innerFrame)
rowFrame.pack()
for j in range(8):
Label(rowFrame, text="Label %s, %s" % (str(i), str(j))).pack(side="left")
root.mainloop()
Diff to Previous Revision
--- revision 12 2017-04-07 19:57:42
+++ revision 13 2017-04-17 20:16:54
@@ -1,4 +1,4 @@
-# Version: 0.10
+# Version: 0.11
# Author: Miguel Martinez Lopez
# Uncomment the next line to see my email
# print("Author's email: ", "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
@@ -7,45 +7,128 @@
from Tkinter import Canvas, Frame
from ttk import Scrollbar
- from Tkconstants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W
+ from Tkconstants import *
except ImportError:
from tkinter import Canvas, Frame
from tkinter.ttk import Scrollbar
- from tkinter.constants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W
+ from tkinter.constants import *
import platform
+OS = platform.system()
+
+def build_mouse_wheel_handler(widget, orient, factor = 1, what="units"):
+ view_command = getattr(widget, orient+'view')
+
+ 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
+
+class Mousewheel_Support(object):
+
+ # implemetnation of singleton pattern
+ _instance = None
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super(Mousewheel_Support, cls).__new__(cls, *args, **kwargs)
+ return cls._instance
+
+ def __init__(self, root, horizontal_factor = 2, vertical_factor=2):
+
+ self._active_area = None
+
+ 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_mouse_wheel, add='+')
+ root.bind_all('<5>', self._on_mouse_wheel, add='+')
+ else:
+ # Windows and MacOS
+ root.bind_all("<MouseWheel>", self._on_mouse_wheel, add='+')
+
+ def _on_mouse_wheel(self,event):
+ if self._active_area:
+ self._active_area.onMouseWheel(event)
+
+ def _on_mouse_enter_scrolling_area(self, widget):
+ self._active_area = widget
+
+ def _on_mouse_leave_scrolling_area(self):
+ self._active_area = None
+
+ def add_support_to(self, widget, xscrollbar=None, yscrollbar=None, what="units", horizontal_factor=None, vertical_factor=None):
+ if xscrollbar is not None and not hasattr(xscrollbar, 'onMouseWheel'):
+ horizontal_factor = horizontal_factor or self.horizontal_factor
+
+ xscrollbar.onMouseWheel = build_mouse_wheel_handler(widget,'x', self.horizontal_factor, what)
+ xscrollbar.bind('<Enter>', lambda event, scrollbar=xscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
+ xscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
+
+ if yscrollbar is not None and not hasattr(yscrollbar, 'onMouseWheel'):
+ vertical_factor = vertical_factor or self.vertical_factor
+
+ yscrollbar.onMouseWheel = build_mouse_wheel_handler(widget,'y', self.vertical_factor, what)
+ yscrollbar.bind('<Enter>', lambda event, scrollbar=yscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
+ yscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
+
+ main_scrollbar = yscrollbar if yscrollbar is not None else xscrollbar
+
+ if main_scrollbar is not None:
+ widget.bind('<Enter>',lambda event: self._on_mouse_enter_scrolling_area(widget))
+ widget.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())
+
+ widget.onMouseWheel = main_scrollbar.onMouseWheel
+
class Scrolling_Area(Frame):
- OS = platform.system()
- def __init__(self, root, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, outer_background=None, inner_frame=Frame, **kw):
- if scroll_horizontally==False and scroll_vertically == False:
- raise Exception("No direction for scrolling indicated")
-
- Frame.__init__(self, root)
+ def __init__(self, master, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, outer_background=None, inner_frame=Frame, **kw):
+ Frame.__init__(self, master)
if outer_background:
self.configure(background=outer_background)
-
- self._active_area = None
-
- if type(mousewheel_speed) == int:
- self.mousewheel_speed = mousewheel_speed
- else:
- raise Exception("mousewheel_speed must be an integer.")
-
- _onMouseWheel = lambda event: self._active_area._onMouseWheel(event) if self._active_area else None
-
- if self.OS == "Linux" :
- root.bind_all('<4>', _onMouseWheel, add='+')
- root.bind_all('<5>', _onMouseWheel, add='+')
- else:
- # Windows and MacOS
- root.bind_all("<MouseWheel>", _onMouseWheel, add='+')
self._canvas = Canvas(self, highlightthickness=0)
self._canvas.grid(row=0, column=0, sticky="nsew")
+
+ if scroll_vertically:
+ self.yscrollbar = Scrollbar(self, orient=VERTICAL)
+ self.yscrollbar.grid(row=0, column=1,sticky=N+S)
+
+ self._canvas.configure(yscrollcommand=self.yscrollbar.set)
+ self.yscrollbar['command']=self._canvas.yview
+ else:
+ self.yscrollbar = None
+
+ if scroll_horizontally:
+ self.xscrollbar = Scrollbar(self, orient=HORIZONTAL)
+ self.xscrollbar.grid(row=1, column=0, sticky=E+W)
+
+ self._canvas.configure(xscrollcommand=self.xscrollbar.set)
+ self.xscrollbar['command']=self._canvas.xview
+ else:
+ self.xscrollbar = None
self.rowconfigure( 0, weight=1)
self.columnconfigure(0, weight=1)
@@ -55,80 +138,16 @@
self._canvas.create_window(0, 0, window=self.innerFrame, anchor='nw', tags="inner_frame")
- self._canvas.bind('<Configure>', self._configure_canvas)
+ self._canvas.bind('<Configure>', self._on_configure_canvas)
- if scroll_vertically:
- self.vscrollbar = Scrollbar(self, orient=VERTICAL)
- self.vscrollbar._onMouseWheel = self._build_function_onMouseWheel('y')
-
- self.vscrollbar.grid(row=0, column=1,sticky=N+S)
+ Mousewheel_Support(self).add_support_to(self._canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar)
+
+ def _on_configure_canvas(self, event):
+ width = max(self.innerFrame.winfo_reqwidth(), event.width)
+ height = max(self.innerFrame.winfo_reqheight(), event.height)
- self._canvas.configure(yscrollcommand=self.vscrollbar.set)
- self.vscrollbar['command']=self._canvas.yview
- else:
- self.vscrollbar = None
-
- if scroll_horizontally:
- self.hscrollbar = Scrollbar(self, orient=HORIZONTAL)
- self.hscrollbar._onMouseWheel = self._build_function_onMouseWheel('x')
-
- self.hscrollbar.grid(row=1, column=0, sticky=E+W)
-
- self._canvas.configure(xscrollcommand=self.hscrollbar.set)
-
- self.hscrollbar['command']=self._canvas.xview
- else:
- self.hscrollbar = None
-
- self._canvas.bind('<Enter>',lambda event: self._set_active_area(self._canvas))
- self._canvas.bind('<Leave>', lambda event: self._unset_active_area())
-
- if self.vscrollbar:
- self.main_scrollbar = self.vscrollbar
- else:
- self.main_scrollbar = self.hscrollbar
-
- self._canvas._onMouseWheel = self.main_scrollbar._onMouseWheel
-
- for scrollbar in (self.hscrollbar, self.vscrollbar):
- if scrollbar is not None:
- scrollbar.bind('<Enter>', lambda event, scrollbar=scrollbar: self._set_active_area(scrollbar) )
- scrollbar.bind('<Leave>', lambda event: self._unset_active_area())
-
- def _configure_canvas(self, event):
- width = max(self.innerFrame.winfo_reqwidth(),self._canvas.winfo_width())
- height = max(self.innerFrame.winfo_reqheight(),self._canvas.winfo_height())
-
- self._canvas.config(scrollregion="0 0 %s %s" % (width, height))
-
- self._canvas.itemconfigure("inner_frame", width=width)
- self._canvas.itemconfigure("inner_frame", height=height)
-
- def _set_active_area(self, widget):
- self._active_area = widget
-
- def _unset_active_area(self):
- self._active_area = None
-
- def _build_function_onMouseWheel(self, orient):
- view_command = getattr(self._canvas, orient+'view')
-
- if self.OS == 'Linux':
- def onMouseWheel(event):
- if event.num == 4:
- view_command("scroll",(-1)*self.mousewheel_speed,"units" )
- elif event.num == 5:
- view_command("scroll",self.mousewheel_speed,"units" )
-
- elif self.OS == 'Windows':
- def onMouseWheel(event):
- view_command("scroll",(-1)*int((event.delta/120)*self.mousewheel_speed),"units" )
-
- elif self.OS == 'Darwin':
- def onMouseWheel(event):
- view_command("scroll",event.delta,"units" )
-
- return onMouseWheel
+ self._canvas.configure(scrollregion="0 0 %s %s" % (width, height))
+ self._canvas.itemconfigure("inner_frame", width=width, height=height)
if __name__== '__main__':
try: