The default handler of pannedwindow is replaced by a rectangle with the color and size that the user wants.
It's similar to jquery Layout plugin: http://layout.jquery-dev.com/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202  | # Author: Miguel Martinez Lopez
#
# Uncomment the next line to see my email
# print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
try:
    from Tkinter import Frame, PanedWindow as Tk_PanedWindow
    from ttk import Label
    from Tkconstants import HORIZONTAL, VERTICAL
except ImportError:
    from tkinter import Frame, PanedWindow as Tk_PanedWindow
    from tkinter.ttk import Label
    from tkinter.constants import HORIZONTAL, VERTICAL
class Handle(Frame):
    def __init__(self, panedwindow, sash_index, disallow_dragging=False, on_click=None, **kw):
        image = kw.pop("image", None)
        Frame.__init__(self, panedwindow, class_="Handle", **kw)
        self._sash_index = sash_index
        
        if image:
            self._event_area = Label(self, image=image)
            self._event_area.pack()            
        else:
            self._event_area = self
        
        self._center = int(self._event_area.winfo_reqwidth()/2), int(self._event_area.winfo_reqheight()/2)
        if disallow_dragging:
            if on_click:
                self._event_area.bind('<Button-1>', lambda event: on_click())
        else:
            self._event_area.bind('<Button-1>', self._initiate_motion)
            self._event_area.bind('<B1-Motion>', self._on_dragging)
            self._event_area.bind('<ButtonRelease-1>', self.master._on_release)
        
        
    def _initiate_motion(self, event) :
        self.master._active_sash = self._sash_index
        self._dx = event.x
        self._dy = event.y
    @property
    def sash_index(self):
        return self._sash_index
    def _on_dragging(self):
        raise NotImplementedError
class Vertical_Handle(Handle):
    def _on_dragging(self, event):
        y = event.y_root - self.master.winfo_rooty() - self._dy
        
        self.master.sash_place(self._sash_index, 1, y)
        self.master._update_position_all_handles()
class Horizontal_Handle(Handle):
    def _on_dragging(self, event):
        x = event.x_root - self.master.winfo_rootx() - self._dx
        self.master.sash_place(self._sash_index, x, 1)
        self.master._update_position_all_handles()
        
class PanedWindow(Tk_PanedWindow):
    
    def __init__(self, master, color="gray", size=60, sashpad=2, disallow_dragging=False, on_click=None, image=None, cursor=None, opaqueresize=True):
        Tk_PanedWindow.__init__(self, master, showhandle = False, orient=self.ORIENT, sashpad=sashpad, opaqueresize=opaqueresize)
    
        self._active_sash = None
        self._on_click = on_click
        self._image = image
        self._color = color
        self._cursor = cursor
        self._configure_callbacks = []
        
        if not opaqueresize:
            disallow_dragging = True
        self._disallow_dragging = disallow_dragging
        self._handle_list = []
        self._list_of_panes = []
        
        if self.ORIENT == VERTICAL:           
            self._width= size
            self._height = 2*sashpad
        else:            
            self._width = 2*sashpad
            self._height= size
        
        if opaqueresize:
            self.bind('<Button-1>', self._on_mark_sash)
            self.bind('<B1-Motion>', self._on_drag_sash)
            self.bind('<ButtonRelease-1>', self._on_release)
        
    def _on_release(self, event):
        handle_index = self._active_sash
        callback_id1 = self._list_of_panes[handle_index+1].bind("<Configure>", lambda event, handle_index=handle_index: self._on_configure_pane(handle_index), "+")
        callback_id2 = self._list_of_panes[handle_index].bind("<Configure>", lambda event, handle_index=handle_index: self._on_configure_pane(handle_index), "+")
        self._configure_callbacks[handle_index] = (callback_id1,callback_id2)
        self._active_sash = None
    def _on_drag_sash(self, event):
        coord_x = event.x
        coord_y = event.y
        Tk_PanedWindow.sash_place(self, self._active_sash, coord_x, coord_y)
        self._update_position_all_handles()
        return "break"
    def add(self, pane, **kwargs):
        Tk_PanedWindow.add(self, pane, **kwargs)
        self._list_of_panes.append(pane)
        quantity_of_panes = len(self._list_of_panes)
        if quantity_of_panes >= 2:
            handle_index = quantity_of_panes-2
            handle = self.HANDLE_CLASS(self, handle_index, bg=self._color, height=self._height, width=self._width, cursor = self._cursor, disallow_dragging=self._disallow_dragging, on_click=self._on_click, image=self._image)
            if self.ORIENT == VERTICAL:
                handle.place(relx=0.5, anchor="c")
            else:
                handle.place(rely=0.5, anchor="c")
            self._handle_list.append(handle)
            callback_id1 = pane.bind("<Configure>", lambda event, handle_index=handle_index: self._on_configure_pane(handle_index), "+")
            callback_id2 = self._list_of_panes[handle_index].bind("<Configure>", lambda event, handle_index=handle_index: self._on_configure_pane(handle_index), "+")
            self._configure_callbacks.append((callback_id1,callback_id2))
    def _on_mark_sash(self, event):
        identity = self.identify(event.x, event.y)
        if len(identity) ==2:
            self._active_sash= handle_index = identity[0]
            callback_id1,callback_id2 = self._configure_callbacks[handle_index]
            
            self._list_of_panes[handle_index+1].unbind(callback_id1)
            self._list_of_panes[handle_index].unbind(callback_id2)
        else:
            self._active_sash = None
class Vertical_PanedWindow(PanedWindow):
    ORIENT = VERTICAL
    HANDLE_CLASS = Vertical_Handle
        
    def _on_configure_pane(self, sash_index):
        x,y = Tk_PanedWindow.sash_coord(self, sash_index)
        self._handle_list[sash_index].place(y=y)
            
    def _update_position_all_handles(self):
        for sash_index, handle in enumerate(self._handle_list):
            x,y = Tk_PanedWindow.sash_coord(self, sash_index)
            handle.place(y=y)
class Horizontal_PanedWindow(PanedWindow):
    ORIENT = HORIZONTAL
    HANDLE_CLASS = Horizontal_Handle
    def _update_position_all_handles(self):
        for sash_index, handle in enumerate(self._handle_list):
            x,y = Tk_PanedWindow.sash_coord(self, sash_index)
            handle.place(x=x)
    def _on_configure_pane(self, sash_index):
        x,y = Tk_PanedWindow.sash_coord(self, sash_index)
        self._handle_list[sash_index].place(x=x)
        
if __name__ == "__main__":
    try:
        from Tkinter import Tk, PhotoImage
    except ImportError:
        from tkinter import Tk
    root = Tk()
    
    # Use for example this image for horizontal panedwindow
    # image = PhotoImage(data="R0lGODlhAwAYAPIAAEBAQGBgYICAgLu7u8zMzAAAAAAAAAAAACH5BAEAAAUALAAAAAADABgAAAMXCCFRI4OUSRVzUNJp24sbt3hZWHQYOCUAOw==")
    image = PhotoImage(data="R0lGODlhGAADAPIFAEBAQGBgYICAgLu7u8zMzAAAAAAAAAAAACH5BAEAAAUALAAAAAAYAAMAAAMaWBJQym61N2UZJTisb96fpxGD4JBmgZ4lKyQAOw==")
    panedwindow = Vertical_PanedWindow(root,  sashpad = 3, image=image)
    panedwindow.pack(fill="both", expand=True)
    
    
    for color in ("red", "blue","green"):
        frame = Frame(panedwindow, width=200, height=200, bg=color)
        panedwindow.add(frame, stretch="always")
    
    root.mainloop()
 | 
Download
Copy to clipboard