Welcome, guest | Sign In | My Account | Store | Cart
# Version: 0.5
# Author: Miguel Martinez Lopez
# Uncomment the next line to see my email
# print("Author's email: ", "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))

try:
    from Tkinter import Canvas
    from ttk import Scrollbar, Frame
    
    from Tkconstants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W
except ImportError:
    from tkinter import Canvas
    from tkinter.ttk import Scrollbar, Frame
    
    from tkinter.constants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W

import platform


class ScrollingArea(Frame):
    OS = platform.system()
    
    def __init__(self, root, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, **kw):
        if scroll_horizontally==False and scroll_vertically == False:
            raise Exception("No direction for scrolling indicated")

        Frame.__init__(self, root, **kw)
        
        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")

        self.rowconfigure( 0, weight=1)
        self.columnconfigure(0, weight=1)
        
        self.interiorFrame= Frame(self._canvas, **kw)
        self.interiorFrame.pack()
        
        self._canvas.create_window(0, 0, window=self.interiorFrame, anchor='nw', tags="inner_frame")
                    
        self._canvas.bind('<Configure>', self._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)
        
            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.interiorFrame.winfo_reqwidth(),self._canvas.winfo_width())
        height = max(self.interiorFrame.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


if __name__== '__main__':
    try:
        from Tkinter import Tk, Label
    except ImportError:
        from tkinter import Tk, Label
    
    root = Tk()
    
    scrolling_area = ScrollingArea(root)
    scrolling_area.pack(expand=1, fill=BOTH)
    
    for i in range(20):
        rowFrame = Frame(scrolling_area.interiorFrame)
        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 6 2017-03-16 14:44:13
+++ revision 7 2017-03-23 22:58:12
@@ -1,33 +1,39 @@
-# Version: 0.4
+# Version: 0.5
 # Author: Miguel Martinez Lopez
 # Uncomment the next line to see my email
 # print("Author's email: ", "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
 
 try:
-    import Tkinter as tk
+    from Tkinter import Canvas
+    from ttk import Scrollbar, Frame
+    
+    from Tkconstants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W
 except ImportError:
-    import tkinter as tk
+    from tkinter import Canvas
+    from tkinter.ttk import Scrollbar, Frame
+    
+    from tkinter.constants import HORIZONTAL, VERTICAL, BOTH, N, S, E, W
 
 import platform
 
 
-class Scrolled_Frame(tk.Frame):
+class ScrollingArea(Frame):
     OS = platform.system()
     
-    def __init__(self, root, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, inner_padx=0, inner_pady=0):
+    def __init__(self, root, mousewheel_speed = 2, scroll_horizontally=True, scroll_vertically=True, **kw):
         if scroll_horizontally==False and scroll_vertically == False:
             raise Exception("No direction for scrolling indicated")
-            
-        tk.Frame.__init__(self, root, borderwidth=0)
+
+        Frame.__init__(self, root, **kw)
         
-        self.activeArea = None
+        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.activeArea._onMouseWheel(event) if self.activeArea else None
+        _onMouseWheel = lambda event: self._active_area._onMouseWheel(event) if self._active_area else None
         
         if self.OS == "Linux" :
             root.bind_all('<4>', _onMouseWheel,  add='+')
@@ -35,77 +41,76 @@
         else:
             # Windows and MacOS
             root.bind_all("<MouseWheel>", _onMouseWheel,  add='+')
-        
-        self.Scrolled_Frame = tk.Canvas(self, highlightthickness=0)
-        self.Scrolled_Frame.grid(row=0, column=0, sticky="nsew")
+
+        self._canvas = Canvas(self, highlightthickness=0)
+        self._canvas.grid(row=0, column=0, sticky="nsew")
 
         self.rowconfigure( 0, weight=1)
         self.columnconfigure(0, weight=1)
         
-        self.innerFrame= tk.Frame(self.Scrolled_Frame, padx=inner_padx, pady=inner_pady)
-        self.innerFrame.pack()
+        self.interiorFrame= Frame(self._canvas, **kw)
+        self.interiorFrame.pack()
         
-        self.Scrolled_Frame.create_window(0, 0, window=self.innerFrame, anchor='nw', tags="inner_frame")
+        self._canvas.create_window(0, 0, window=self.interiorFrame, anchor='nw', tags="inner_frame")
                     
-        self.Scrolled_Frame.bind('<Configure>', self._configure_widget)
-        
-        
+        self._canvas.bind('<Configure>', self._configure_canvas)
+
         if scroll_vertically:
-            self.vscrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
+            self.vscrollbar = Scrollbar(self, orient=VERTICAL)
             self.vscrollbar._onMouseWheel = self._build_function_onMouseWheel('y')
             
-            self.vscrollbar.grid(row=0, column=1,sticky="ns")
+            self.vscrollbar.grid(row=0, column=1,sticky=N+S)
         
-            self.Scrolled_Frame.configure(yscrollcommand=self.vscrollbar.set)
-            self.vscrollbar['command']=self.Scrolled_Frame.yview
+            self._canvas.configure(yscrollcommand=self.vscrollbar.set)
+            self.vscrollbar['command']=self._canvas.yview
         else:
             self.vscrollbar = None
             
 
         if scroll_horizontally:
-            self.hscrollbar = tk.Scrollbar(self, orient=tk.HORIZONTAL)
+            self.hscrollbar = Scrollbar(self, orient=HORIZONTAL)
             self.hscrollbar._onMouseWheel = self._build_function_onMouseWheel('x')
             
-            self.hscrollbar.grid(row=1, column=0, sticky="ew")
+            self.hscrollbar.grid(row=1, column=0, sticky=E+W)
             
-            self.Scrolled_Frame.configure(xscrollcommand=self.hscrollbar.set)
+            self._canvas.configure(xscrollcommand=self.hscrollbar.set)
             
-            self.hscrollbar['command']=self.Scrolled_Frame.xview
+            self.hscrollbar['command']=self._canvas.xview
         else:
             self.hscrollbar = None
             
-        self.Scrolled_Frame.bind('<Enter>',lambda event: self._setActiveArea(self.Scrolled_Frame))
-        self.Scrolled_Frame.bind('<Leave>', lambda event: self._unsetActiveArea())
+        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.Scrolled_Frame._onMouseWheel = self.main_scrollbar._onMouseWheel
+        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._setActiveArea(scrollbar) )
-                scrollbar.bind('<Leave>', lambda event: self._unsetActiveArea())
+                scrollbar.bind('<Enter>', lambda event, scrollbar=scrollbar: self._set_active_area(scrollbar) )
+                scrollbar.bind('<Leave>', lambda event: self._unset_active_area())
 
-    def _configure_widget(self, event):
-        width = max(self.innerFrame.winfo_reqwidth(),self.Scrolled_Frame.winfo_width())
-        height = max(self.innerFrame.winfo_reqheight(),self.Scrolled_Frame.winfo_height())
+    def _configure_canvas(self, event):
+        width = max(self.interiorFrame.winfo_reqwidth(),self._canvas.winfo_width())
+        height = max(self.interiorFrame.winfo_reqheight(),self._canvas.winfo_height())
         
-        self.Scrolled_Frame.config(scrollregion="0 0 %s %s" % (width, height))
+        self._canvas.config(scrollregion="0 0 %s %s" % (width, height))
         
-        self.Scrolled_Frame.itemconfigure("inner_frame", width=width)
-        self.Scrolled_Frame.itemconfigure("inner_frame", height=height)
+        self._canvas.itemconfigure("inner_frame", width=width)
+        self._canvas.itemconfigure("inner_frame", height=height)
     
-    def _setActiveArea(self, widget):
-        self.activeArea = widget
+    def _set_active_area(self, widget):
+        self._active_area = widget
 
-    def _unsetActiveArea(self):
-        self.activeArea = None
+    def _unset_active_area(self):
+        self._active_area = None
 
     def _build_function_onMouseWheel(self, orient):
-        view_command = getattr(self.Scrolled_Frame, orient+'view')
+        view_command = getattr(self._canvas, orient+'view')
         
         if self.OS == 'Linux':
             def onMouseWheel(event):                
@@ -126,15 +131,20 @@
 
 
 if __name__== '__main__':
-    root = tk.Tk()
+    try:
+        from Tkinter import Tk, Label
+    except ImportError:
+        from tkinter import Tk, Label
     
-    scrolling_area = Scrolled_Frame(root)
-    scrolling_area.pack(expand=1, fill=tk.BOTH)
+    root = Tk()
+    
+    scrolling_area = ScrollingArea(root)
+    scrolling_area.pack(expand=1, fill=BOTH)
     
     for i in range(20):
-        rowFrame = tk.Frame(scrolling_area.innerFrame)
+        rowFrame = Frame(scrolling_area.interiorFrame)
         rowFrame.pack()
         for j in range(8):
-            tk.Label(rowFrame, text="Label %s, %s" % (str(i), str(j))).pack(side=tk.LEFT)
+            Label(rowFrame, text="Label %s, %s" % (str(i), str(j))).pack(side="left")
 
     root.mainloop()

History