Welcome, guest | Sign In | My Account | Store | Cart

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/

Python, 202 lines
  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()